public async Task MoveLoadingNodeToLast()
        {
            var clusterSize = 3;
            var settings    = new Dictionary <string, string>()
            {
                [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)]                 = 300.ToString(),
                [RavenConfiguration.GetKey(x => x.Cluster.StabilizationTime)]               = "1",
                [RavenConfiguration.GetKey(x => x.Cluster.MoveToRehabGraceTime)]            = "5",
                [RavenConfiguration.GetKey(x => x.Cluster.RotatePreferredNodeGraceTime)]    = "1",
                [RavenConfiguration.GetKey(x => x.Replication.ReplicationMinimalHeartbeat)] = "15",
            };

            var cluster = await CreateRaftCluster(clusterSize, false, 0, watcherCluster : true, customSettings : settings);

            using (var store = GetDocumentStore(new Options
            {
                Server = cluster.Leader,
                ReplicationFactor = clusterSize
            }))
            {
                var tcs = new TaskCompletionSource <DocumentDatabase>();

                var databaseName = store.Database;
                using (var session = store.OpenSession())
                {
                    session.Store(new User {
                        Name = "Karmel"
                    }, "users/1");
                    session.SaveChanges();

                    Assert.True(await WaitForDocumentInClusterAsync <User>(cluster.Nodes, databaseName, "users/1", _ => true, TimeSpan.FromSeconds(5)));
                }

                var record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database));

                var preferred = Servers.Single(s => s.ServerStore.NodeTag == record.Topology.Members[0]);

                int val;
                using (new DisposableAction(() =>
                {
                    preferred.ServerStore.DatabasesLandlord.DatabasesCache.TryRemove(databaseName, out var t);
                    if (t == tcs.Task)
                    {
                        tcs.SetCanceled();
                    }
                }))
                {
                    var t = preferred.ServerStore.DatabasesLandlord.DatabasesCache.Replace(databaseName, tcs.Task);
                    t.Result.Dispose();

                    Assert.True(await WaitForValueAsync(async() =>
                    {
                        record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database));
                        return(record.Topology.Members[0] != preferred.ServerStore.NodeTag);
                    }, true));

                    val = await WaitForValueAsync(async() => await GetRehabCount(store, databaseName), 1);

                    Assert.Equal(1, val);
                    val = await WaitForValueAsync(async() => await GetMembersCount(store, databaseName), clusterSize - 1);

                    Assert.Equal(clusterSize - 1, val);
                }

                val = await WaitForValueAsync(async() => await GetRehabCount(store, databaseName), 0);

                Assert.Equal(0, val);
                val = await WaitForValueAsync(async() => await GetMembersCount(store, databaseName), 2);

                Assert.Equal(clusterSize, val);
            }
        }
예제 #2
0
        public async Task ShouldKeepPullingDocsAfterServerRestart()
        {
            var dataPath = NewDataPath();

            IDocumentStore store  = null;
            RavenServer    server = null;
            SubscriptionWorker <dynamic> subscriptionWorker = null;

            try
            {
                server = GetNewServer(runInMemory: false, customSettings: new Dictionary <string, string>()
                {
                    [RavenConfiguration.GetKey(x => x.Core.DataDirectory)] = dataPath
                });

                store = new DocumentStore()
                {
                    Urls     = new[] { server.ServerStore.GetNodeHttpServerUrl() },
                    Database = "RavenDB_2627",
                }.Initialize();

                var doc    = new DatabaseRecord(store.Database);
                var result = store.Maintenance.Server.Send(new CreateDatabaseOperationWithoutNameValidation(doc));
                await WaitForRaftIndexToBeAppliedInCluster(result.RaftCommandIndex, _reasonableWaitTime);

                using (var session = store.OpenSession())
                {
                    session.Store(new User());
                    session.Store(new User());
                    session.Store(new User());
                    session.Store(new User());

                    session.SaveChanges();
                }

                var id = store.Subscriptions.Create(new SubscriptionCreationOptions <User>());

                subscriptionWorker = store.Subscriptions.GetSubscriptionWorker(new SubscriptionWorkerOptions(id)
                {
                    TimeToWaitBeforeConnectionRetry = TimeSpan.FromSeconds(1),
                    MaxDocsPerBatch = 1
                });


                var gotBatch = new ManualResetEventSlim();
                var gotArek  = new ManualResetEventSlim();
                var t        = subscriptionWorker.Run(x =>
                {
                    gotBatch.Set();

                    foreach (var item in x.Items)
                    {
                        if (item.Id == "users/arek")
                        {
                            gotArek.Set();
                        }
                    }
                });

                Assert.True(gotBatch.Wait(_reasonableWaitTime));

                Server.ServerStore.DatabasesLandlord.UnloadDirectly(store.Database);

                for (int i = 0; i < 150; i++)
                {
                    try
                    {
                        using (var session = store.OpenSession())
                        {
                            session.Store(new User(), "users/arek");
                            session.SaveChanges();
                        }
                        break;
                    }
                    catch
                    {
                        Thread.Sleep(25);
                        if (i > 100)
                        {
                            throw;
                        }
                    }
                }

                Assert.True(gotArek.Wait(_reasonableWaitTime));
            }
            finally
            {
                subscriptionWorker?.Dispose();
                store?.Dispose();
                server.Dispose();
            }
        }
예제 #3
0
        private void ValidateLocalRootPath()
        {
            if (LocalRootPath == null)
            {
                return;
            }

            var directoryInfo = new DirectoryInfo(LocalRootPath.FullPath);

            if (directoryInfo.Exists == false)
            {
                throw new ArgumentException($"The backup path '{LocalRootPath.FullPath}' defined in the configuration under '{RavenConfiguration.GetKey(x => x.Backup.LocalRootPath)}' doesn't exist.");
            }
        }
예제 #4
0
        protected virtual DocumentStore GetDocumentStore(Options options = null, [CallerMemberName] string caller = null)
        {
            try
            {
                lock (_getDocumentStoreSync)
                {
                    options = options ?? Options.Default;
                    var serverToUse = options.Server ?? Server;

                    var name = GetDatabaseName(caller);

                    if (options.ModifyDatabaseName != null)
                    {
                        name = options.ModifyDatabaseName(name) ?? name;
                    }

                    var hardDelete  = true;
                    var runInMemory = options.RunInMemory;

                    var pathToUse = options.Path;
                    if (pathToUse == null)
                    {
                        pathToUse = NewDataPath(name);
                    }
                    else
                    {
                        hardDelete  = false;
                        runInMemory = false;
                    }

                    var doc = new DatabaseRecord(name)
                    {
                        Settings =
                        {
                            [RavenConfiguration.GetKey(x => x.Replication.ReplicationMinimalHeartbeat)] = "1",
                            [RavenConfiguration.GetKey(x => x.Replication.RetryReplicateAfter)]         = "1",
                            [RavenConfiguration.GetKey(x => x.Core.RunInMemory)]   = runInMemory.ToString(),
                            [RavenConfiguration.GetKey(x => x.Core.DataDirectory)] = pathToUse,
                            [RavenConfiguration.GetKey(x => x.Core.ThrowIfAnyIndexCannotBeOpened)] = "true",
                            [RavenConfiguration.GetKey(x => x.Indexing.MinNumberOfMapAttemptsAfterWhichBatchWillBeCanceledIfRunningLowOnMemory)] = int.MaxValue.ToString(),
                        }
                    };

                    if (options.Encrypted)
                    {
                        SetupForEncryptedDatabase(options, name, serverToUse, doc);
                    }

                    options.ModifyDatabaseRecord?.Invoke(doc);

                    var store = new DocumentStore
                    {
                        Urls        = UseFiddler(serverToUse.WebUrl),
                        Database    = name,
                        Certificate = options.ClientCertificate
                    };

                    options.ModifyDocumentStore?.Invoke(store);

                    //This gives too much error details in most cases, we don't need this now
                    store.RequestExecutorCreated += (sender, executor) =>
                    {
                        executor.AdditionalErrorInformation += sb => sb.AppendLine().Append(GetLastStatesFromAllServersOrderedByTime());
                    };

                    store.Initialize();

                    if (options.CreateDatabase)
                    {
                        if (IsGlobalOrLocalServer(serverToUse))
                        {
                            CheckIfDatabaseExists(serverToUse, name);
                        }
                        else
                        {
                            Servers.ForEach(server => CheckIfDatabaseExists(server, name));
                        }

                        DatabasePutResult result;

                        if (options.AdminCertificate != null)
                        {
                            using (var adminStore = new DocumentStore
                            {
                                Urls = UseFiddler(serverToUse.WebUrl),
                                Database = name,
                                Certificate = options.AdminCertificate
                            }.Initialize())
                            {
                                result = adminStore.Maintenance.Server.Send(new CreateDatabaseOperation(doc, options.ReplicationFactor));
                            }
                        }
                        else
                        {
                            result = store.Maintenance.Server.Send(new CreateDatabaseOperation(doc, options.ReplicationFactor));
                        }

                        Assert.True(result.RaftCommandIndex > 0); //sanity check

                        if (IsGlobalOrLocalServer(serverToUse))
                        {
                            // skip 'wait for requests' on DocumentDatabase dispose
                            ApplySkipDrainAllRequestsToDatabase(serverToUse, name);
                        }
                        else
                        {
                            var timeout = TimeSpan.FromMinutes(Debugger.IsAttached ? 5 : 1);
                            AsyncHelpers.RunSync(async() => await WaitForRaftIndexToBeAppliedInCluster(result.RaftCommandIndex, timeout));

                            // skip 'wait for requests' on DocumentDatabase dispose
                            Servers.ForEach(server => ApplySkipDrainAllRequestsToDatabase(server, name));
                        }
                    }

                    store.BeforeDispose += (sender, args) =>
                    {
                        if (CreatedStores.TryRemove(store) == false)
                        {
                            return; // can happen if we are wrapping the store inside sharded one
                        }
                        DeleteDatabaseResult result = null;
                        if (options.DeleteDatabaseOnDispose)
                        {
                            result = DeleteDatabase(options, serverToUse, name, hardDelete, store);
                        }

                        if (IsGlobalOrLocalServer(serverToUse) == false &&
                            result != null)
                        {
                            var timeout = TimeSpan.FromMinutes(Debugger.IsAttached ? 5 : 1);
                            AsyncHelpers.RunSync(async() => await WaitForRaftIndexToBeAppliedInCluster(result.RaftCommandIndex, timeout));
                        }
                    };
                    CreatedStores.Add(store);

                    return(store);
                }
            }
            catch (TimeoutException te)
            {
                throw new TimeoutException($"{te.Message} {Environment.NewLine} {te.StackTrace}{Environment.NewLine}Servers states:{Environment.NewLine}{GetLastStatesFromAllServersOrderedByTime()}");
            }
        }
예제 #5
0
        public Task SetupUnsecured()
        {
            AssertOnlyInSetupMode();

            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
                using (var setupInfoJson = context.ReadForMemory(RequestBodyStream(), "setup-unsecured"))
                {
                    // Making sure we don't have leftovers from previous setup
                    try
                    {
                        using (var tx = context.OpenWriteTransaction())
                        {
                            ServerStore.Engine.DeleteTopology(context);
                            tx.Commit();
                        }
                    }
                    catch (Exception)
                    {
                        // ignored
                    }

                    var setupInfo = JsonDeserializationServer.UnsecuredSetupInfo(setupInfoJson);

                    BlittableJsonReaderObject settingsJson;
                    using (var fs = new FileStream(ServerStore.Configuration.ConfigPath, FileMode.Open, FileAccess.Read))
                    {
                        settingsJson = context.ReadForMemory(fs, "settings-json");
                    }

                    settingsJson.Modifications = new DynamicJsonValue(settingsJson)
                    {
                        [RavenConfiguration.GetKey(x => x.Licensing.EulaAccepted)]          = true,
                        [RavenConfiguration.GetKey(x => x.Core.SetupMode)]                  = nameof(SetupMode.Unsecured),
                        [RavenConfiguration.GetKey(x => x.Security.UnsecuredAccessAllowed)] = nameof(UnsecuredAccessAddressRange.PublicNetwork)
                    };

                    if (setupInfo.Port == 0)
                    {
                        setupInfo.Port = 8080;
                    }

                    settingsJson.Modifications[RavenConfiguration.GetKey(x => x.Core.ServerUrls)] = string.Join(";", setupInfo.Addresses.Select(ip => IpAddressToUrl(ip, setupInfo.Port)));

                    if (setupInfo.TcpPort == 0)
                    {
                        setupInfo.TcpPort = 38888;
                    }

                    settingsJson.Modifications[RavenConfiguration.GetKey(x => x.Core.TcpServerUrls)] = string.Join(";", setupInfo.Addresses.Select(ip => IpAddressToUrl(ip, setupInfo.TcpPort, "tcp")));

                    if (setupInfo.EnableExperimentalFeatures)
                    {
                        settingsJson.Modifications[RavenConfiguration.GetKey(x => x.Core.FeaturesAvailability)] = FeaturesAvailability.Experimental;
                    }

                    var modifiedJsonObj = context.ReadObject(settingsJson, "modified-settings-json");

                    var indentedJson = SetupManager.IndentJsonString(modifiedJsonObj.ToString());
                    SetupManager.WriteSettingsJsonLocally(ServerStore.Configuration.ConfigPath, indentedJson);
                }

            return(NoContent());
        }
예제 #6
0
        public async Task DontKickFromClusterOnElectionTimeoutMismatch()
        {
            var cluster = await CreateRaftCluster(2, shouldRunInMemory : false);

            var result = await DisposeServerAndWaitForFinishOfDisposalAsync(cluster.Nodes[0]);

            await cluster.Nodes[1].ServerStore.WaitForState(RachisState.Candidate, CancellationToken.None);

            cluster.Nodes[0] = GetNewServer(new ServerCreationOptions
            {
                DeletePrevious = false,
                RunInMemory    = false,
                DataDirectory  = result.DataDirectory,
                CustomSettings = new Dictionary <string, string>
                {
                    [RavenConfiguration.GetKey(x => x.Core.ServerUrls)]         = result.Url,
                    [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)] = 600.ToString(),
                }
            });

            using (var cts = new CancellationTokenSource(10_000))
            {
                var t1 = cluster.Nodes[0].ServerStore.WaitForState(RachisState.Leader, cts.Token);
                var t2 = cluster.Nodes[1].ServerStore.WaitForState(RachisState.Leader, cts.Token);

                var task = await Task.WhenAny(t1, t2);

                if (task == t1)
                {
                    Assert.NotEqual(RachisState.Passive, cluster.Nodes[1].ServerStore.Engine.CurrentState);
                }
                else
                {
                    Assert.NotEqual(RachisState.Passive, cluster.Nodes[0].ServerStore.Engine.CurrentState);
                }
            }

            result = await DisposeServerAndWaitForFinishOfDisposalAsync(cluster.Nodes[1]);

            cluster.Nodes[1] = GetNewServer(new ServerCreationOptions
            {
                DeletePrevious = false,
                RunInMemory    = false,
                DataDirectory  = result.DataDirectory,
                CustomSettings = new Dictionary <string, string>
                {
                    [RavenConfiguration.GetKey(x => x.Core.ServerUrls)]         = result.Url,
                    [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)] = 600.ToString(),
                }
            });

            using (var cts = new CancellationTokenSource(10_000))
            {
                var t1 = cluster.Nodes[0].ServerStore.WaitForState(RachisState.Leader, cts.Token);
                var t2 = cluster.Nodes[1].ServerStore.WaitForState(RachisState.Leader, cts.Token);

                var task = await Task.WhenAny(t1, t2);

                if (task == t1)
                {
                    Assert.Equal(RachisState.Follower, cluster.Nodes[1].ServerStore.Engine.CurrentState);
                }
                else
                {
                    Assert.Equal(RachisState.Follower, cluster.Nodes[0].ServerStore.Engine.CurrentState);
                }
            }
        }
예제 #7
0
        public async Task DontRemoveNodeWhileItHasNotReplicatedDocs()
        {
            var databaseName = GetDatabaseName();
            var leader       = await CreateRaftClusterAndGetLeader(3, shouldRunInMemory : false);

            using (var leaderStore = new DocumentStore
            {
                Urls = new[] { leader.WebUrl },
                Database = databaseName,
            })
            {
                leaderStore.Initialize();
                var topology = new DatabaseTopology
                {
                    Members = new List <string>
                    {
                        "B",
                        "C"
                    },
                    DynamicNodesDistribution = true
                };
                var(index, dbGroupNodes) = await CreateDatabaseInCluster(new DatabaseRecord
                {
                    DatabaseName = databaseName,
                    Topology     = topology
                }, 2, leader.WebUrl);
                await WaitForRaftIndexToBeAppliedInCluster(index, TimeSpan.FromSeconds(30));

                using (var session = leaderStore.OpenSession())
                {
                    session.Store(new User(), "users/1");
                    session.SaveChanges();
                }
                var dbToplogy = (await leaderStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName))).Topology;
                Assert.Equal(2, dbToplogy.AllNodes.Count());
                Assert.Equal(0, dbToplogy.Promotables.Count);
                Assert.True(await WaitForDocumentInClusterAsync <User>(topology, databaseName, "users/1", null, TimeSpan.FromSeconds(30)));

                var serverA  = Servers.Single(s => s.ServerStore.NodeTag == "A");
                var urlsA    = new[] { serverA.WebUrl };
                var dataDirA = serverA.Configuration.Core.DataDirectory.FullPath.Split('/').Last();
                DisposeServerAndWaitForFinishOfDisposal(serverA);

                var serverB  = Servers.Single(s => s.ServerStore.NodeTag == "B");
                var urlsB    = new[] { serverB.WebUrl };
                var dataDirB = serverB.Configuration.Core.DataDirectory.FullPath.Split('/').Last();
                DisposeServerAndWaitForFinishOfDisposal(serverB);

                // write doc only to C
                using (var session = leaderStore.OpenSession())
                {
                    session.Store(new User(), "users/2");
                    session.SaveChanges();
                }

                var serverC  = Servers.Single(s => s.ServerStore.NodeTag == "C");
                var urlsC    = new[] { serverC.WebUrl };
                var dataDirC = serverC.Configuration.Core.DataDirectory.FullPath.Split('/').Last();
                DisposeServerAndWaitForFinishOfDisposal(serverC);

                Servers[0] = GetNewServer(
                    new ServerCreationOptions {
                    CustomSettings = new Dictionary <string, string> {
                        { RavenConfiguration.GetKey(x => x.Core.ServerUrls), urlsA[0] }
                    },
                    RunInMemory    = false,
                    DeletePrevious = false,
                    PartialPath    = dataDirA
                });
                Servers[1] = GetNewServer(new ServerCreationOptions
                {
                    CustomSettings = new Dictionary <string, string> {
                        { RavenConfiguration.GetKey(x => x.Core.ServerUrls), urlsB[0] }
                    },
                    RunInMemory    = false,
                    DeletePrevious = false,
                    PartialPath    = dataDirB
                });
                await Task.Delay(TimeSpan.FromSeconds(10));

                Assert.Equal(2, await WaitForValueAsync(async() => await GetMembersCount(leaderStore, databaseName), 2));
                Assert.Equal(1, await WaitForValueAsync(async() => await GetRehabCount(leaderStore, databaseName), 1));

                using (var session = leaderStore.OpenSession())
                {
                    session.Store(new User(), "users/3");
                    session.SaveChanges();
                }
                Assert.True(await WaitForDocumentInClusterAsync <User>(new DatabaseTopology
                {
                    Members = new List <string> {
                        "A", "B"
                    }
                }, databaseName, "users/3", null, TimeSpan.FromSeconds(10)));

                Servers[2] = GetNewServer(new ServerCreationOptions
                {
                    CustomSettings = new Dictionary <string, string> {
                        { RavenConfiguration.GetKey(x => x.Core.ServerUrls), urlsC[0] }
                    },
                    RunInMemory    = false,
                    DeletePrevious = false,
                    PartialPath    = dataDirC
                });
                Assert.Equal(2, await WaitForValueAsync(async() => await GetMembersCount(leaderStore, databaseName), 2));
                Assert.Equal(0, await WaitForValueAsync(async() => await GetRehabCount(leaderStore, databaseName), 0, 30_000));

                dbToplogy = (await leaderStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName))).Topology;
                Assert.True(await WaitForDocumentInClusterAsync <User>(dbToplogy, databaseName, "users/3", null, TimeSpan.FromSeconds(10)));

                dbToplogy = (await leaderStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName))).Topology;
                Assert.Equal(2, dbToplogy.AllNodes.Count());
                Assert.Equal(2, dbToplogy.Members.Count);
                Assert.Equal(0, dbToplogy.Rehabs.Count);

                Assert.True(await WaitForDocumentInClusterAsync <User>(dbToplogy, databaseName, "users/1", null, TimeSpan.FromSeconds(10)));
                Assert.True(await WaitForDocumentInClusterAsync <User>(dbToplogy, databaseName, "users/3", null, TimeSpan.FromSeconds(10)));
                Assert.True(await WaitForDocumentInClusterAsync <User>(dbToplogy, databaseName, "users/2", null, TimeSpan.FromSeconds(30)));

                dbToplogy = (await leaderStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName))).Topology;
                Assert.Equal(2, dbToplogy.AllNodes.Count());
                Assert.Equal(2, dbToplogy.Members.Count);
                Assert.Equal(0, dbToplogy.Rehabs.Count);
            }
        }
예제 #8
0
        internal void ValidatePublicUrls()
        {
            if (PublicServerUrl.HasValue)
            {
                ValidatePublicUrl(PublicServerUrl.Value.UriValue, RavenConfiguration.GetKey(x => x.Core.PublicServerUrl));
            }
            else if (ServerUrls.Length > 1)
            {
                throw new ArgumentException($"Configuration key '{RavenConfiguration.GetKey(x => x.Core.PublicServerUrl)}' must be specified when there is more than one '{RavenConfiguration.GetKey(x => x.Core.ServerUrls)}'.");
            }

            if (PublicTcpServerUrl.HasValue)
            {
                ValidatePublicUrl(PublicTcpServerUrl.Value.UriValue, RavenConfiguration.GetKey(x => x.Core.PublicTcpServerUrl));
            }
            else if (TcpServerUrls != null && TcpServerUrls.Length > 1)
            {
                throw new ArgumentException($"Configuration key '{RavenConfiguration.GetKey(x => x.Core.PublicTcpServerUrl)}' must be specified when there is more than one '{RavenConfiguration.GetKey(x => x.Core.TcpServerUrls)}'.");
            }
        }
예제 #9
0
        public async Task CanGetLetsEncryptCertificateAndRenewIt()
        {
            var settingPath         = Path.Combine(NewDataPath(forceCreateDir: true), "settings.json");
            var defaultSettingsPath = new PathSetting("settings.default.json").FullPath;

            File.Copy(defaultSettingsPath, settingPath, true);

            UseNewLocalServer(customConfigPath: settingPath);

            // Use this when testing against pebble
            //var acmeStaging = "https://localhost:14000/";

            var acmeStaging = "https://acme-staging-v02.api.letsencrypt.org/";

            Server.Configuration.Core.AcmeUrl = acmeStaging;
            Server.ServerStore.Configuration.Core.SetupMode = SetupMode.Initial;

            var    domain = "RavenClusterTest" + Environment.MachineName.Replace("-", "");
            string email;
            string rootDomain;

            Server.ServerStore.EnsureNotPassive();
            var license = Server.ServerStore.LoadLicense();

            using (var store = GetDocumentStore())
                using (var commands = store.Commands())
                    using (Server.ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext context))
                    {
                        var command = new ClaimDomainCommand(store.Conventions, context, new ClaimDomainInfo
                        {
                            Domain  = domain,
                            License = license
                        });

                        await commands.RequestExecutor.ExecuteAsync(command, commands.Context);

                        Assert.True(command.Result.RootDomains.Length > 0);
                        rootDomain = command.Result.RootDomains[0];
                        email      = command.Result.Email;
                    }

            var tcpListener = new TcpListener(IPAddress.Loopback, 0);

            tcpListener.Start();
            var port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;

            tcpListener.Stop();

            var setupInfo = new SetupInfo
            {
                Domain             = domain,
                RootDomain         = rootDomain,
                ModifyLocalServer  = false, // N/A here
                RegisterClientCert = false, // N/A here
                Password           = null,
                Certificate        = null,
                LocalNodeTag       = "A",
                License            = license,
                Email          = email,
                NodeSetupInfos = new Dictionary <string, SetupInfo.NodeInfo>()
                {
                    ["A"] = new SetupInfo.NodeInfo
                    {
                        Port      = port,
                        Addresses = new List <string>
                        {
                            "127.0.0.1"
                        }
                    }
                }
            };

            X509Certificate2 serverCert;

            byte[] serverCertBytes;
            string firstServerCertThumbprint;
            BlittableJsonReaderObject settingsJsonObject;

            using (var store = GetDocumentStore())
                using (var commands = store.Commands())
                    using (Server.ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext context))
                    {
                        var command = new SetupLetsEncryptCommand(store.Conventions, context, setupInfo);

                        await commands.RequestExecutor.ExecuteAsync(command, commands.Context);

                        Assert.True(command.Result.Length > 0);

                        var zipBytes = command.Result;

                        try
                        {
                            settingsJsonObject        = SetupManager.ExtractCertificatesAndSettingsJsonFromZip(zipBytes, "A", context, out serverCertBytes, out serverCert, out _, out _, out _, out _);
                            firstServerCertThumbprint = serverCert.Thumbprint;
                        }
                        catch (Exception e)
                        {
                            throw new InvalidOperationException("Unable to extract setup information from the zip file.", e);
                        }

                        // Finished the setup wizard, need to restart the server.
                        // Since cannot restart we'll create a new server loaded with the new certificate and settings and use the server cert to connect to it

                        settingsJsonObject.TryGet(RavenConfiguration.GetKey(x => x.Security.CertificatePassword), out string certPassword);
                        settingsJsonObject.TryGet(RavenConfiguration.GetKey(x => x.Security.CertificateLetsEncryptEmail), out string letsEncryptEmail);
                        settingsJsonObject.TryGet(RavenConfiguration.GetKey(x => x.Core.PublicServerUrl), out string publicServerUrl);
                        settingsJsonObject.TryGet(RavenConfiguration.GetKey(x => x.Core.ServerUrls), out string serverUrl);
                        settingsJsonObject.TryGet(RavenConfiguration.GetKey(x => x.Core.SetupMode), out SetupMode setupMode);
                        settingsJsonObject.TryGet(RavenConfiguration.GetKey(x => x.Core.ExternalIp), out string externalIp);

                        var tempFileName = GetTempFileName();
                        File.WriteAllBytes(tempFileName, serverCertBytes);

                        IDictionary <string, string> customSettings = new ConcurrentDictionary <string, string>
                        {
                            [RavenConfiguration.GetKey(x => x.Security.CertificatePath)]             = tempFileName,
                            [RavenConfiguration.GetKey(x => x.Security.CertificateLetsEncryptEmail)] = letsEncryptEmail,
                            [RavenConfiguration.GetKey(x => x.Security.CertificatePassword)]         = certPassword,
                            [RavenConfiguration.GetKey(x => x.Core.PublicServerUrl)] = publicServerUrl,
                            [RavenConfiguration.GetKey(x => x.Core.ServerUrls)]      = serverUrl,
                            [RavenConfiguration.GetKey(x => x.Core.SetupMode)]       = setupMode.ToString(),
                            [RavenConfiguration.GetKey(x => x.Core.ExternalIp)]      = externalIp,
                            [RavenConfiguration.GetKey(x => x.Core.AcmeUrl)]         = acmeStaging
                        };

                        DoNotReuseServer(customSettings);
                    }

            Server.Dispose();

            UseNewLocalServer();

            // Note: because we use a staging lets encrypt cert, the chain is not trusted.
            // It only works because in the TestBase ctor we do:
            // RequestExecutor.ServerCertificateCustomValidationCallback += (msg, cert, chain, errors) => true;

            using (var store = GetDocumentStore(new Options
            {
                AdminCertificate = serverCert,
                ClientCertificate = serverCert
            }))
                using (var commands = store.Commands())
                    using (Server.ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext context))
                    {
                        Server.ServerStore.EnsureNotPassive();
                        Assert.Equal(firstServerCertThumbprint, Server.Certificate.Certificate.Thumbprint);

                        Server.Time.UtcDateTime = () => DateTime.UtcNow.AddDays(80);

                        var mre = new ManualResetEventSlim();

                        Server.ServerCertificateChanged += (sender, args) => mre.Set();

                        var command = new ForceRenewCertCommand(store.Conventions, context);

                        await commands.RequestExecutor.ExecuteAsync(command, commands.Context);

                        Assert.True(command.Result.Success, "ForceRenewCertCommand returned false");

                        var result = mre.Wait(Debugger.IsAttached ? TimeSpan.FromMinutes(10) : TimeSpan.FromMinutes(4));

                        if (result == false && Server.RefreshTask.IsCompleted)
                        {
                            if (Server.RefreshTask.IsFaulted || Server.RefreshTask.IsCanceled)
                            {
                                Assert.True(result,
                                            $"Refresh task failed to complete successfully. Exception: {Server.RefreshTask.Exception}");
                            }

                            Assert.True(result, "Refresh task completed successfully, waited too long for the cluster cert to be replaced");
                        }

                        Assert.True(result, "Refresh task didn't complete. Waited too long for the cluster cert to be replaced");

                        Assert.NotEqual(firstServerCertThumbprint, Server.Certificate.Certificate.Thumbprint);
                    }
        }
예제 #10
0
        private static void BeforeSchemaUpgrade(StorageEnvironment storageEnvironment, ServerStore serverStore)
        {
            // doing this before the schema upgrade to allow to downgrade in case we cannot start the server

            using (var contextPool = new TransactionContextPool(storageEnvironment, serverStore.Configuration.Memory.MaxContextSizeToKeep))
            {
                var license = serverStore.LoadLicense(contextPool);
                if (license == null)
                {
                    return;
                }

                var licenseStatus = LicenseManager.GetLicenseStatus(license);
                if (licenseStatus.Expiration >= RavenVersionAttribute.Instance.ReleaseDate)
                {
                    return;
                }

                string licenseJson = null;
                var    fromPath    = false;
                if (string.IsNullOrEmpty(serverStore.Configuration.Licensing.License) == false)
                {
                    licenseJson = serverStore.Configuration.Licensing.License;
                }
                else if (File.Exists(serverStore.Configuration.Licensing.LicensePath.FullPath))
                {
                    try
                    {
                        licenseJson = File.ReadAllText(serverStore.Configuration.Licensing.LicensePath.FullPath);
                        fromPath    = true;
                    }
                    catch
                    {
                        // expected
                    }
                }

                var errorMessage = $"Cannot start the RavenDB server because the expiration date of current license ({FormattedDateTime(licenseStatus.Expiration ?? DateTime.MinValue)}) " +
                                   $"is before the release date of this version ({FormattedDateTime(RavenVersionAttribute.Instance.ReleaseDate)})";

                string expiredLicenseMessage = "";
                if (string.IsNullOrEmpty(licenseJson) == false)
                {
                    if (LicenseHelper.TryDeserializeLicense(licenseJson, out License localLicense))
                    {
                        var localLicenseStatus = LicenseManager.GetLicenseStatus(localLicense);
                        if (localLicenseStatus.Expiration >= RavenVersionAttribute.Instance.ReleaseDate)
                        {
                            serverStore.LicenseManager.OnBeforeInitialize += () => serverStore.LicenseManager.TryActivateLicense(throwOnActivationFailure: false);
                            return;
                        }

                        var configurationKey =
                            fromPath ? RavenConfiguration.GetKey(x => x.Licensing.LicensePath) : RavenConfiguration.GetKey(x => x.Licensing.License);
                        expiredLicenseMessage = localLicense.Id == license.Id
                            ? ". You can update current license using the setting.json file"
                            : $". The license '{localLicense.Id}' obtained from '{configurationKey}' with expiration date of '{FormattedDateTime(localLicenseStatus.Expiration ?? DateTime.MinValue)}' is also expired.";
                    }
                    else
                    {
                        errorMessage += ". Could not parse the license from setting.json file.";
                        throw new LicenseExpiredException(errorMessage);
                    }
                }

                var licenseStorage = new LicenseStorage();
                licenseStorage.Initialize(storageEnvironment, contextPool);

                var buildInfo = licenseStorage.GetBuildInfo();
                if (buildInfo != null)
                {
                    errorMessage += $" You can downgrade to the latest build that was working ({buildInfo.FullVersion})";
                }
                if (string.IsNullOrEmpty(expiredLicenseMessage) == false)
                {
                    errorMessage += expiredLicenseMessage;
                }
                throw new LicenseExpiredException(errorMessage);
예제 #11
0
        public static int Main(string[] args)
        {
            NativeMemory.GetCurrentUnmanagedThreadId = () => (ulong)Pal.rvn_get_current_thread_id();

            UseOnlyInvariantCultureInRavenDB();

            SetCurrentDirectoryToServerPath();

            string[] configurationArgs;
            try
            {
                configurationArgs = CommandLineSwitches.Process(args);
            }
            catch (CommandParsingException commandParsingException)
            {
                Console.WriteLine(commandParsingException.Message);
                CommandLineSwitches.ShowHelp();
                return(1);
            }

            if (CommandLineSwitches.ShouldShowHelp)
            {
                CommandLineSwitches.ShowHelp();
                return(0);
            }

            if (CommandLineSwitches.PrintVersionAndExit)
            {
                Console.WriteLine(ServerVersion.FullVersion);
                return(0);
            }

            new WelcomeMessage(Console.Out).Print();

            var targetSettingsFile = new PathSetting(string.IsNullOrEmpty(CommandLineSwitches.CustomConfigPath)
                ? "settings.json"
                : CommandLineSwitches.CustomConfigPath);

            var destinationSettingsFile = new PathSetting("settings.default.json");

            if (File.Exists(targetSettingsFile.FullPath) == false &&
                File.Exists(destinationSettingsFile.FullPath)) //just in case
            {
                File.Copy(destinationSettingsFile.FullPath, targetSettingsFile.FullPath);
            }

            var configuration = RavenConfiguration.CreateForServer(null, CommandLineSwitches.CustomConfigPath);

            if (configurationArgs != null)
            {
                configuration.AddCommandLine(configurationArgs);
            }

            configuration.Initialize();

            LoggingSource.UseUtcTime = configuration.Logs.UseUtcTime;
            LoggingSource.Instance.MaxFileSizeInBytes = configuration.Logs.MaxFileSize.GetValue(SizeUnit.Bytes);
            LoggingSource.Instance.SetupLogMode(
                configuration.Logs.Mode,
                configuration.Logs.Path.FullPath,
                configuration.Logs.RetentionTime?.AsTimeSpan,
                configuration.Logs.RetentionSize?.GetValue(SizeUnit.Bytes),
                configuration.Logs.Compress
                );

            if (Logger.IsInfoEnabled)
            {
                Logger.Info($"Logging to {configuration.Logs.Path} set to {configuration.Logs.Mode} level.");
            }

            LatestVersionCheck.Instance.Initialize(configuration.Updates);

            if (Logger.IsOperationsEnabled)
            {
                Logger.Operations(RavenCli.GetInfoText());
            }

            if (WindowsServiceRunner.ShouldRunAsWindowsService())
            {
                try
                {
                    WindowsServiceRunner.Run(CommandLineSwitches.ServiceName, configuration, configurationArgs);
                }
                catch (Exception e)
                {
                    if (Logger.IsInfoEnabled)
                    {
                        Logger.Info("Error running Windows Service", e);
                    }

                    return(1);
                }

                return(0);
            }

            RestartServer = () =>
            {
                RestartServerMre.Set();
                ShutdownServerMre.Set();
            };

            var rerun = false;
            RavenConfiguration configBeforeRestart = configuration;

            do
            {
                if (rerun)
                {
                    Console.WriteLine("\nRestarting Server...");

                    configuration = RavenConfiguration.CreateForServer(null, CommandLineSwitches.CustomConfigPath);

                    if (configurationArgs != null)
                    {
                        var argsAfterRestart = PostSetupCliArgumentsUpdater.Process(
                            configurationArgs, configBeforeRestart, configuration);

                        configuration.AddCommandLine(argsAfterRestart);
                        configBeforeRestart = configuration;
                    }

                    configuration.Initialize();
                }

                try
                {
                    using (var server = new RavenServer(configuration))
                    {
                        try
                        {
                            try
                            {
                                server.OpenPipes();
                            }
                            catch (Exception e)
                            {
                                if (Logger.IsInfoEnabled)
                                {
                                    Logger.Info("Unable to OpenPipe. Admin Channel will not be available to the user", e);
                                }
                                Console.WriteLine("Warning: Admin Channel is not available:" + e);
                            }

                            server.BeforeSchemaUpgrade = x => BeforeSchemaUpgrade(x, server.ServerStore);
                            server.Initialize();

                            if (CommandLineSwitches.PrintServerId)
                            {
                                Console.WriteLine($"Server ID is {server.ServerStore.GetServerId()}.");
                            }

                            new RuntimeSettings(Console.Out).Print();

                            if (rerun == false && CommandLineSwitches.LaunchBrowser)
                            {
                                BrowserHelper.OpenStudioInBrowser(server.ServerStore.GetNodeHttpServerUrl());
                            }

                            new ClusterMessage(Console.Out, server.ServerStore).Print();

                            var prevColor = Console.ForegroundColor;
                            Console.Write("Server available on: ");
                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.WriteLine($"{server.ServerStore.GetNodeHttpServerUrl()}");
                            Console.ForegroundColor = prevColor;

                            var tcpServerStatus = server.GetTcpServerStatus();
                            if (tcpServerStatus.Listeners.Count > 0)
                            {
                                prevColor = Console.ForegroundColor;
                                Console.Write("Tcp listening on ");
                                Console.ForegroundColor = ConsoleColor.Green;
                                Console.WriteLine($"{string.Join(", ", tcpServerStatus.Listeners.Select(l => l.LocalEndpoint))}");
                                Console.ForegroundColor = prevColor;
                            }

                            Console.WriteLine("Server started, listening to requests...");

                            prevColor = Console.ForegroundColor;
                            Console.ForegroundColor = ConsoleColor.DarkGray;
                            Console.WriteLine("TIP: type 'help' to list the available commands.");
                            Console.ForegroundColor = prevColor;

                            if (configuration.Storage.IgnoreInvalidJournalErrors == true)
                            {
                                var message =
                                    $"Server is running in dangerous mode because {RavenConfiguration.GetKey(x => x.Storage.IgnoreInvalidJournalErrors)} was set. " +
                                    "It means that storages of databases, indexes and system one will be loaded regardless missing or corrupted journal files which " +
                                    "are mandatory to properly load the storage. " +
                                    "This switch is meant to be use only for recovery purposes. Please make sure that you won't use it on regular basis. ";

                                if (Logger.IsOperationsEnabled)
                                {
                                    Logger.Operations(message);
                                }

                                prevColor = Console.ForegroundColor;
                                Console.ForegroundColor = ConsoleColor.Red;
                                Console.WriteLine(message);
                                Console.ForegroundColor = prevColor;
                            }

                            IsRunningNonInteractive = false;
                            rerun = CommandLineSwitches.NonInteractive ||
                                    configuration.Core.SetupMode == SetupMode.Initial
                                ? RunAsNonInteractive()
                                : RunInteractive(server);

                            Console.WriteLine("Starting shut down...");
                            if (Logger.IsInfoEnabled)
                            {
                                Logger.Info("Server is shutting down");
                            }
                        }
                        catch (Exception e)
                        {
                            string message = null;
                            if (e.InnerException is AddressInUseException)
                            {
                                message =
                                    $"{Environment.NewLine}Port might be already in use.{Environment.NewLine}Try running with an unused port.{Environment.NewLine}" +
                                    $"You can change the port using one of the following options:{Environment.NewLine}" +
                                    $"1) Change the ServerUrl property in setting.json file.{Environment.NewLine}" +
                                    $"2) Run the server from the command line with --ServerUrl option.{Environment.NewLine}" +
                                    $"3) Add RAVEN_ServerUrl to the Environment Variables.{Environment.NewLine}" +
                                    "For more information go to https://ravendb.net/l/EJS81M/5.0";
                            }
                            else if (e is SocketException && PlatformDetails.RunningOnPosix)
                            {
                                const string extension = ".dll";
                                var          ravenPath = typeof(RavenServer).Assembly.Location;
                                if (ravenPath.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
                                {
                                    ravenPath = ravenPath.Substring(0, ravenPath.Length - extension.Length);
                                }

                                message =
                                    $"{Environment.NewLine}In Linux low-level port (below 1024) will need a special permission, " +
                                    $"if this is your case please run{Environment.NewLine}" +
                                    $"sudo setcap CAP_NET_BIND_SERVICE=+eip {ravenPath}";
                            }
                            else if (e.InnerException is LicenseExpiredException)
                            {
                                message = e.InnerException.Message;
                            }

                            if (Logger.IsOperationsEnabled)
                            {
                                Logger.Operations("Failed to initialize the server", e);
                                Logger.Operations(message);
                            }

                            Console.WriteLine(message);

                            Console.WriteLine();

                            Console.WriteLine(e);

                            return(-1);
                        }
                    }

                    Console.WriteLine("Shutdown completed");
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error during shutdown");
                    Console.WriteLine(e);
                    return(-2);
                }
                finally
                {
                    if (Logger.IsOperationsEnabled)
                    {
                        Logger.OperationsAsync("Server has shut down").Wait(TimeSpan.FromSeconds(15));
                    }
                    ShutdownCompleteMre.Set();
                }
            } while (rerun);

            return(0);
        }
예제 #12
0
        public async Task RestoreAndReplicateCounters()
        {
            var backupPath = NewDataPath(suffix: "BackupFolder");

            using (var server = GetNewServer(new Dictionary <string, string>
            {
                [RavenConfiguration.GetKey(x => x.Replication.MaxItemsCount)] = 1.ToString()
            }))
            {
                using (var store1 = GetDocumentStore(new Options
                {
                    Server = server
                }))
                    using (var store2 = GetDocumentStore(new Options
                    {
                        Server = server,
                        CreateDatabase = false
                    }))
                        using (var store3 = GetDocumentStore(new Options
                        {
                            Server = server
                        }))
                        {
                            using (var session = store1.OpenAsyncSession())
                            {
                                await session.StoreAsync(new User { Name = "Name1" }, "users/1");

                                await session.StoreAsync(new User { Name = "Name2" }, "users/2");

                                session.CountersFor("users/1").Increment("likes", 100);
                                session.CountersFor("users/2").Increment("downloads", 500);

                                await session.SaveChangesAsync();
                            }

                            using (var session = store1.OpenAsyncSession())
                            {
                                // need to be in a different transaction in order to split the replication into batches
                                session.CountersFor("users/1").Increment("dislikes", 200);
                                await session.SaveChangesAsync();
                            }

                            await Backup(backupPath, store1);
                            await Restore(backupPath, store2);

                            var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation());

                            Assert.Equal(2, stats.CountOfDocuments);
                            Assert.Equal(3, stats.CountOfCounters);

                            using (var session = store2.OpenAsyncSession())
                            {
                                await AssertCounters(session);
                            }

                            await SetupReplicationAsync(store2, store3);

                            using (var session = store2.OpenAsyncSession())
                            {
                                await session.StoreAsync(new User(), "marker");

                                await session.SaveChangesAsync();
                            }

                            Assert.NotNull(WaitForDocumentToReplicate <User>(store3, "marker", 10_000));

                            using (var session = store3.OpenAsyncSession())
                            {
                                await AssertCounters(session);
                            }
                        }
            }
        }
예제 #13
0
        protected async Task <(List <RavenServer> Nodes, RavenServer Leader)> CreateRaftCluster(int numberOfNodes, bool shouldRunInMemory   = true, int?leaderIndex = null, bool useSsl = false,
                                                                                                IDictionary <string, string> customSettings = null)
        {
            leaderIndex = leaderIndex ?? _random.Next(0, numberOfNodes);
            RavenServer leader          = null;
            var         serversToPorts  = new Dictionary <RavenServer, string>();
            var         clustersServers = new List <RavenServer>();

            _electionTimeoutInMs = Math.Max(300, numberOfNodes * 80);
            for (var i = 0; i < numberOfNodes; i++)
            {
                customSettings = customSettings ?? new Dictionary <string, string>()
                {
                    [RavenConfiguration.GetKey(x => x.Cluster.MoveToRehabGraceTime)] = "1",
                    [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)]      = _electionTimeoutInMs.ToString(),
                    [RavenConfiguration.GetKey(x => x.Cluster.StabilizationTime)]    = "1",
                };
                string serverUrl;

                if (useSsl)
                {
                    serverUrl = UseFiddlerUrl("https://127.0.0.1:0");
                    SetupServerAuthentication(customSettings, serverUrl);
                }
                else
                {
                    serverUrl = UseFiddlerUrl("http://127.0.0.1:0");
                    customSettings[RavenConfiguration.GetKey(x => x.Core.ServerUrls)] = serverUrl;
                }

                var server = GetNewServer(customSettings, runInMemory: shouldRunInMemory);
                var port   = Convert.ToInt32(server.ServerStore.GetNodeHttpServerUrl().Split(':')[2]);
                var prefix = useSsl ? "https" : "http";
                serverUrl = UseFiddlerUrl($"{prefix}://127.0.0.1:{port}");
                Servers.Add(server);
                clustersServers.Add(server);

                serversToPorts.Add(server, serverUrl);
                if (i == leaderIndex)
                {
                    server.ServerStore.EnsureNotPassive();
                    leader = server;
                }
            }
            for (var i = 0; i < numberOfNodes; i++)
            {
                if (i == leaderIndex)
                {
                    continue;
                }
                var follower = clustersServers[i];
                // ReSharper disable once PossibleNullReferenceException
                await leader.ServerStore.AddNodeToClusterAsync(serversToPorts[follower]);

                await follower.ServerStore.WaitForTopology(Leader.TopologyModification.Voter);
            }
            // ReSharper disable once PossibleNullReferenceException
            var condition = await leader.ServerStore.WaitForState(RachisState.Leader, CancellationToken.None).WaitAsync(numberOfNodes * _electionTimeoutInMs * 5);

            var states = string.Empty;

            if (condition == false)
            {
                states = GetLastStatesFromAllServersOrderedByTime();
            }
            Assert.True(condition, "The leader has changed while waiting for cluster to become stable. All nodes status: " + states);
            return(clustersServers, leader);
        }
예제 #14
0
        public static void UnlikelyFailAuthorization(HttpContext context, string database,
                                                     RavenServer.AuthenticateConnection feature,
                                                     AuthorizationStatus authorizationStatus)
        {
            string message;

            if (feature == null ||
                feature.Status == RavenServer.AuthenticationStatus.None ||
                feature.Status == RavenServer.AuthenticationStatus.NoCertificateProvided)
            {
                message = "This server requires client certificate for authentication, but none was provided by the client.";
            }
            else
            {
                var name = feature.Certificate.FriendlyName;
                if (string.IsNullOrWhiteSpace(name))
                {
                    name = feature.Certificate.Subject;
                }
                if (string.IsNullOrWhiteSpace(name))
                {
                    name = feature.Certificate.ToString(false);
                }

                name += $"(Thumbprint: {feature.Certificate.Thumbprint})";

                if (feature.Status == RavenServer.AuthenticationStatus.UnfamiliarCertificate)
                {
                    message =
                        $"The supplied client certificate '{name}' is unknown to the server. In order to register your certificate please contact your system administrator.";
                }
                else if (feature.Status == RavenServer.AuthenticationStatus.UnfamiliarIssuer)
                {
                    message =
                        $"The supplied client certificate '{name}' is unknown to the server but has a known Public Key Pinning Hash. Will not use it to authenticate because the issuer is unknown. To fix this, the admin can register the pinning hash of the *issuer* certificate: '{feature.IssuerHash}' in the '{RavenConfiguration.GetKey(x => x.Security.WellKnownIssuerHashes)}' configuration entry.";
                }
                else if (feature.Status == RavenServer.AuthenticationStatus.Allowed)
                {
                    message = $"Could not authorize access to {(database ?? "the server")} using provided client certificate '{name}'.";
                }
                else if (feature.Status == RavenServer.AuthenticationStatus.Operator)
                {
                    message = $"Insufficient security clearance to access {(database ?? "the server")} using provided client certificate '{name}'.";
                }
                else if (feature.Status == RavenServer.AuthenticationStatus.Expired)
                {
                    message =
                        $"The supplied client certificate '{name}' has expired on {feature.Certificate.NotAfter:D}. Please contact your system administrator in order to obtain a new one.";
                }
                else if (feature.Status == RavenServer.AuthenticationStatus.NotYetValid)
                {
                    message = $"The supplied client certificate '{name}'cannot be used before {feature.Certificate.NotBefore:D}";
                }
                else
                {
                    message = "Access to the server was denied.";
                }
            }
            switch (authorizationStatus)
            {
            case AuthorizationStatus.ClusterAdmin:
                message += " ClusterAdmin access is required but not given to this certificate";
                break;

            case AuthorizationStatus.Operator:
                message += " Operator/ClusterAdmin access is required but not given to this certificate";
                break;

            case AuthorizationStatus.DatabaseAdmin:
                message += " DatabaseAdmin access is required but not given to this certificate";
                break;
            }

            context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
            using (var ctx = JsonOperationContext.ShortTermSingleUse())
                using (var writer = new BlittableJsonTextWriter(ctx, context.Response.Body))
                {
                    DrainRequest(ctx, context);

                    if (RavenServerStartup.IsHtmlAcceptable(context))
                    {
                        context.Response.StatusCode          = (int)HttpStatusCode.Redirect;
                        context.Response.Headers["Location"] = "/auth-error.html?err=" + Uri.EscapeDataString(message);
                        return;
                    }

                    ctx.Write(writer,
                              new DynamicJsonValue
                    {
                        ["Type"]    = "InvalidAuth",
                        ["Message"] = message
                    });
                }
        }
예제 #15
0
        public async Task MarkPolicyAfterRollup()
        {
            DefaultClusterSettings[RavenConfiguration.GetKey(x => x.Tombstones.CleanupInterval)] = 1.ToString();
            var cluster = await CreateRaftCluster(3, watcherCluster : true);

            using (var store = GetDocumentStore(new Options {
                Server = cluster.Leader, ReplicationFactor = 3, RunInMemory = false
            }))
            {
                var raw    = new RawTimeSeriesPolicy();
                var config = new TimeSeriesConfiguration
                {
                    Collections = new Dictionary <string, TimeSeriesCollectionConfiguration>
                    {
                        ["Users"] = new TimeSeriesCollectionConfiguration
                        {
                            RawPolicy = raw,
                            Policies  = new List <TimeSeriesPolicy> {
                                new TimeSeriesPolicy("ByMinute", TimeSpan.FromMinutes(10))
                            }
                        }
                    },
                    PolicyCheckFrequency = TimeSpan.FromSeconds(1)
                };
                DatabaseRecordWithEtag record = null;
                await WaitForValueAsync(async() =>
                {
                    record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database));
                    return(record.Topology.Members.Count);
                }, 3);

                Assert.Equal(3, record.Topology.Members.Count);
                var firstNode = record.Topology.Members[0];
                await store.Maintenance.SendAsync(new ConfigureTimeSeriesOperation(config));

                var now = new DateTime(2021, 6, 1, 10, 7, 29, DateTimeKind.Utc);
                foreach (var server in Servers)
                {
                    var database = await server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);

                    database.Time.UtcDateTime = () => now;
                }

                var baseline = now.Add(-TimeSpan.FromMinutes(15));

                using (var session = store.OpenSession())
                {
                    var id = "users/karmel/0";
                    session.Store(new User {
                        Name = "Karmel"
                    }, id);
                    for (int i = 0; i < 15; i++)
                    {
                        session.TimeSeriesFor(id, "Heartrate")
                        .Append(baseline.AddMinutes(i), i);
                    }

                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                {
                    session.Store(new User(), "marker");
                    session.SaveChanges();
                    Assert.True(await WaitForDocumentInClusterAsync <User>(cluster.Nodes, store.Database, "marker", null, TimeSpan.FromSeconds(15)));
                }

                var res = new Dictionary <string, int>();
                foreach (var server in Servers)
                {
                    var database = await server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);

                    var tss = database.DocumentsStorage.TimeSeriesStorage;
                    await database.TimeSeriesPolicyRunner.RunRollups();

                    var name = config.Collections["Users"].Policies[0].GetTimeSeriesName("Heartrate");
                    WaitForValue(() =>
                    {
                        using (var session = store.OpenSession())
                        {
                            var val = session.TimeSeriesFor("users/karmel/0", name)
                                      .Get(DateTime.MinValue, DateTime.MaxValue);
                            return(val != null);
                        }
                    }, true);

                    using (var session = store.OpenSession())
                    {
                        var val = session.TimeSeriesFor("users/karmel/0", name)
                                  .Get(DateTime.MinValue, DateTime.MaxValue).Length;
                        res.Add(server.ServerStore.NodeTag, val);
                        Assert.True(val > 0);
                    }
                }

                await WaitForValueAsync(async() =>
                {
                    record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database));
                    return(record.Topology.Members.Count);
                }, 3);

                Assert.Equal(3, record.Topology.Members.Count);
                var firstNode2 = record.Topology.Members[0];
                Assert.Equal(firstNode2, firstNode);

                record = store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database)).Result;
                var list = record.Topology.Members;
                list.Reverse();
                await store.Maintenance.Server.SendAsync(new ReorderDatabaseMembersOperation(store.Database, list));
                await WaitForValueAsync(async() =>
                {
                    record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database));
                    return(record.Topology.Members.Count);
                }, 3);

                Assert.Equal(3, record.Topology.Members.Count);
                firstNode2 = record.Topology.Members[0];
                Assert.NotEqual(firstNode2, firstNode);

                await Task.Delay(1000);

                foreach (var server in Servers)
                {
                    var database = await server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);

                    database.Time.UtcDateTime = () => now.AddMinutes(10);
                    await database.TimeSeriesPolicyRunner.RunRollups();
                }

                foreach (var server in Servers)
                {
                    WaitForValue(() =>
                    {
                        using (var session = store.OpenSession())
                        {
                            var name = config.Collections["Users"].Policies[0].GetTimeSeriesName("Heartrate");
                            var val  = session.TimeSeriesFor("users/karmel/0", name)
                                       .Get(DateTime.MinValue, DateTime.MaxValue);
                            return(val.Length > res[server.ServerStore.NodeTag]);
                        }
                    }, true);
                }

                using (var session = store.OpenSession())
                {
                    var name = config.Collections["Users"].Policies[0].GetTimeSeriesName("Heartrate");
                    var val  = session.TimeSeriesFor("users/karmel/0", name)
                               .Get(DateTime.MinValue, DateTime.MaxValue);

                    Assert.True(val.Length > res[Servers[0].ServerStore.NodeTag]);
                }


                await WaitForValueAsync(async() =>
                {
                    record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database));
                    return(record.Topology.Members.Count);
                }, 3);

                Assert.Equal(3, record.Topology.Members.Count);
                firstNode2 = record.Topology.Members[0];
                Assert.NotEqual(firstNode2, firstNode);
            }
        }
예제 #16
0
 public static string GetError(string source, string dest)
 {
     return($"You are able to reach '{dest}', but the remote node failed to reach you back on '{source}'.{Environment.NewLine}" +
            $"Please validate the correctness of your '{RavenConfiguration.GetKey(x => x.Core.PublicServerUrl)}', '{RavenConfiguration.GetKey(x => x.Core.PublicTcpServerUrl)}' configuration and the firewall rules.{Environment.NewLine}" +
            $"Please visit https://ravendb.net/l/QUPWS7/4.1 for the RavenDB setup instructions.");
 }
예제 #17
0
        public async Task SingleResultTest()
        {
            DefaultClusterSettings[RavenConfiguration.GetKey(x => x.Tombstones.CleanupInterval)] = 1.ToString();
            var cluster = await CreateRaftCluster(3, watcherCluster : true);

            using (var store = GetDocumentStore(new Options {
                Server = cluster.Leader, ReplicationFactor = 3, RunInMemory = false
            }))
            {
                var raw    = new RawTimeSeriesPolicy();
                var config = new TimeSeriesConfiguration
                {
                    Collections = new Dictionary <string, TimeSeriesCollectionConfiguration>
                    {
                        ["Users"] = new TimeSeriesCollectionConfiguration
                        {
                            RawPolicy = raw,
                            Policies  = new List <TimeSeriesPolicy> {
                                new TimeSeriesPolicy("ByMinute", TimeSpan.FromSeconds(60))
                            }
                        }
                    },
                    PolicyCheckFrequency = TimeSpan.FromSeconds(1)
                };

                await store.Maintenance.SendAsync(new ConfigureTimeSeriesOperation(config));

                var now = DateTime.UtcNow;

                var baseline = now.AddSeconds(-120);
                using (var session = store.OpenSession())
                {
                    var id = "users/karmel/0";
                    session.Store(new User {
                        Name = "Karmel"
                    }, id);
                    for (int i = 0; i < 120; i++)
                    {
                        session.TimeSeriesFor(id, "Heartrate")
                        .Append(baseline.AddSeconds(i), i);
                    }

                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                {
                    session.Store(new User(), "marker");
                    session.SaveChanges();
                    Assert.True(await WaitForDocumentInClusterAsync <User>(cluster.Nodes, store.Database, "marker", null, TimeSpan.FromSeconds(15)));
                }

                var database = await Servers[0].ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);
                using (database.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx))
                {
                    using (var tx = ctx.OpenReadTransaction())
                    {
                        var name   = config.Collections["Users"].Policies[0].GetTimeSeriesName("Heartrate");
                        var reader = database.DocumentsStorage.TimeSeriesStorage.GetReader(ctx, "users/karmel/0", "Heartrate", baseline.AddSeconds(120), DateTime.MaxValue);
                        Assert.True(reader.Last() == null);
                    }
                }
            }
        }
예제 #18
0
        internal static void Validate(RavenConfiguration configuration)
        {
            foreach (var sUrl in configuration.Core.ServerUrls)
            {
                var serverUrl = sUrl.ToLowerInvariant();

                if (Uri.TryCreate(serverUrl, UriKind.Absolute, out var uri) == false)
                {
                    throw new UriFormatException("Unable to parse URL - " + serverUrl);
                }

                var isServerUrlHttps = uri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase);

                var serverAddresses                    = DetermineServerIp(uri);
                var unsecuredAccessAddressRange        = configuration.Security.UnsecuredAccessAllowed;
                var serverIsWithinUnsecuredAccessRange = serverAddresses.Any(x => SecurityUtils.IsUnsecuredAccessAllowedForAddress(unsecuredAccessAddressRange, x));

                if (configuration.Security.AuthenticationEnabled)
                {
                    if (isServerUrlHttps == false)
                    {
                        throw new InvalidOperationException(
                                  $"When the server certificate in either `{RavenConfiguration.GetKey(x => x.Security.CertificatePath)}` or `{RavenConfiguration.GetKey(x => x.Security.CertificateExec)}`  is specified, the `{RavenConfiguration.GetKey(x => x.Core.ServerUrls)}` must be using https, but was " +
                                  serverUrl);
                    }
                }
                else
                {
                    if (isServerUrlHttps)
                    {
                        throw new InvalidOperationException($"Configured server address { string.Join(", ", configuration.Core.ServerUrls) } requires HTTPS. Please set up certification information under { RavenConfiguration.GetKey(x => x.Security.CertificatePath) } configuration key.");
                    }

                    if (serverIsWithinUnsecuredAccessRange == false)
                    {
                        configuration.Security.UnsecureAccessWarningMessage =
                            $"Configured {RavenConfiguration.GetKey(x => x.Core.ServerUrls)} \"{string.Join(", ", configuration.Core.ServerUrls)}\" is not set within allowed unsecured access address range - { configuration.Security.UnsecuredAccessAllowed }. Use a server url within unsecure access address range ({RavenConfiguration.GetKey(x => x.Security.UnsecuredAccessAllowed)} option) or fill in server certificate information.";
                        configuration.Security.IsUnsecureAccessSetupValid = false;
                    }
                }

                if (configuration.Security.IsUnsecureAccessSetupValid.HasValue == false)
                {
                    configuration.Security.IsUnsecureAccessSetupValid = true;
                }
            }
        }
예제 #19
0
        public async Task MoveToPassiveWhenRefusedConnectionFromAllNodes()
        {
            //DebuggerAttachedTimeout.DisableLongTimespan = true;
            var clusterSize  = 3;
            var databaseName = GetDatabaseName();
            var leader       = await CreateRaftClusterAndGetLeader(clusterSize, false, 0, customSettings : new Dictionary <string, string>()
            {
                [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)] = "600"
            });

            using (var store = new DocumentStore
            {
                Urls = new[] { leader.WebUrl },
                Database = databaseName
            }.Initialize())
            {
                var doc            = new DatabaseRecord(databaseName);
                var databaseResult = await store.Maintenance.Server.SendAsync(new CreateDatabaseOperation(doc, clusterSize));

                Assert.Equal(clusterSize, databaseResult.Topology.Members.Count);
                await WaitForRaftIndexToBeAppliedInCluster(databaseResult.RaftCommandIndex, TimeSpan.FromSeconds(10));

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(new User());

                    await session.SaveChangesAsync();
                }
                var dataDir = Servers[1].Configuration.Core.DataDirectory.FullPath.Split('/').Last();
                var urls    = new[] { Servers[1].WebUrl };
                var nodeTag = Servers[1].ServerStore.NodeTag;
                // kill the process and remove the node from topology
                DisposeServerAndWaitForFinishOfDisposal(Servers[1]);

                await ActionWithLeader((l) => l.ServerStore.RemoveFromClusterAsync(nodeTag));

                using (leader.ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
                {
                    var val = await WaitForValueAsync(() =>
                    {
                        using (context.OpenReadTransaction())
                        {
                            return(Servers[2].ServerStore.GetClusterTopology(context).AllNodes.Count);
                        }
                    }, clusterSize - 1);

                    Assert.Equal(clusterSize - 1, val);
                    val = await WaitForValueAsync(() =>
                    {
                        using (context.OpenReadTransaction())
                        {
                            return(Servers[0].ServerStore.GetClusterTopology(context).AllNodes.Count);
                        }
                    }, clusterSize - 1);

                    Assert.Equal(clusterSize - 1, val);
                }
                // bring the node back to live and ensure that he moves to passive state
                Servers[1] = GetNewServer(
                    new ServerCreationOptions
                {
                    CustomSettings = new Dictionary <string, string>
                    {
                        { RavenConfiguration.GetKey(x => x.Core.PublicServerUrl), urls[0] },
                        { RavenConfiguration.GetKey(x => x.Core.ServerUrls), urls[0] },
                        { RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout), "600" }
                    },
                    RunInMemory    = false,
                    DeletePrevious = false,
                    PartialPath    = dataDir
                });

                Assert.True(await Servers[1].ServerStore.WaitForState(RachisState.Passive, CancellationToken.None).WaitAsync(TimeSpan.FromSeconds(30)), "1st assert");
                // rejoin the node to the cluster

                await ActionWithLeader((l) => l.ServerStore.AddNodeToClusterAsync(urls[0], nodeTag));

                Assert.True(await Servers[1].ServerStore.WaitForState(RachisState.Follower, CancellationToken.None).WaitAsync(TimeSpan.FromSeconds(30)), "2nd assert");
            }
        }
예제 #20
0
        public async Task ShouldWork()
        {
            var backupPath = NewDataPath(suffix: "BackupFolder");

            using (var store = GetDocumentStore(new Options
            {
                ModifyDatabaseRecord = record => record.Settings[RavenConfiguration.GetKey(x => x.PerformanceHints.MaxNumberOfResults)] = "1"
            }))
            {
                store.Maintenance.Send(new CreateSampleDataOperation());

                WaitForIndexing(store);

                using (var session = store.OpenSession())
                {
                    session.Query <Employee>().ToList(); // this will generate performance hint
                }

                var database = await GetDatabase(store.Database);

                database.NotificationCenter.Paging.UpdatePaging(null);

                int beforeBackupAlertCount;
                using (database.NotificationCenter.GetStored(out var actions))
                    beforeBackupAlertCount = actions.Count();

                Assert.True(beforeBackupAlertCount > 0);

                var beforeBackupStats = store.Maintenance.Send(new GetStatisticsOperation());

                var config = new PeriodicBackupConfiguration
                {
                    BackupType    = BackupType.Snapshot,
                    LocalSettings = new LocalSettings
                    {
                        FolderPath = backupPath
                    },
                    IncrementalBackupFrequency = "* * * * *" //every minute
                };

                var backupTaskId = (store.Maintenance.Send(new UpdatePeriodicBackupOperation(config))).TaskId;
                store.Maintenance.Send(new StartBackupOperation(true, backupTaskId));
                var operation = new GetPeriodicBackupStatusOperation(backupTaskId);
                SpinWait.SpinUntil(() =>
                {
                    var getPeriodicBackupResult = store.Maintenance.Send(operation);
                    return(getPeriodicBackupResult.Status?.LastEtag > 0);
                }, TimeSpan.FromSeconds(15));

                // restore the database with a different name
                var restoredDatabaseName = $"restored_database_snapshot_{Guid.NewGuid().ToString()}";
                var restoreConfiguration = new RestoreBackupConfiguration
                {
                    BackupLocation = Directory.GetDirectories(backupPath).First(),
                    DatabaseName   = restoredDatabaseName
                };

                var restoreBackupTask = new RestoreBackupOperation(restoreConfiguration);
                var restoreResult     = store.Maintenance.Server.Send(restoreBackupTask);
                restoreResult.WaitForCompletion(TimeSpan.FromSeconds(30));

                var afterRestoreStats = store.Maintenance.ForDatabase(restoredDatabaseName).Send(new GetStatisticsOperation());

                var restoredDatabase = await GetDatabase(restoredDatabaseName);

                int afterRestoreAlertCount;
                using (restoredDatabase.NotificationCenter.GetStored(out var actions))
                    afterRestoreAlertCount = actions.Count();

                Assert.True(afterRestoreAlertCount > 0);

                var indexesPath      = restoredDatabase.Configuration.Indexing.StoragePath;
                var indexesDirectory = new DirectoryInfo(indexesPath.FullPath);
                Assert.True(indexesDirectory.Exists);
                Assert.Equal(afterRestoreStats.CountOfIndexes, indexesDirectory.GetDirectories().Length);

                Assert.NotEqual(beforeBackupStats.DatabaseId, afterRestoreStats.DatabaseId);
                Assert.Equal(beforeBackupStats.CountOfAttachments, afterRestoreStats.CountOfAttachments);
                Assert.Equal(beforeBackupStats.CountOfConflicts, afterRestoreStats.CountOfConflicts);
                Assert.Equal(beforeBackupStats.CountOfDocuments, afterRestoreStats.CountOfDocuments);
                Assert.Equal(beforeBackupStats.CountOfDocumentsConflicts, afterRestoreStats.CountOfDocumentsConflicts);
                Assert.Equal(beforeBackupStats.CountOfIndexes, afterRestoreStats.CountOfIndexes);
                Assert.Equal(beforeBackupStats.CountOfRevisionDocuments, afterRestoreStats.CountOfRevisionDocuments);
                Assert.Equal(beforeBackupStats.CountOfTombstones, afterRestoreStats.CountOfTombstones);
                Assert.Equal(beforeBackupStats.CountOfUniqueAttachments, afterRestoreStats.CountOfUniqueAttachments);
            }
        }
예제 #21
0
        public async Task ChangeUrlOfMultiNodeCluster()
        {
            var fromSeconds = TimeSpan.FromSeconds(8);

            var    databaseName = GetDatabaseName();
            var    groupSize    = 3;
            var    newUrl       = "http://127.0.0.1:0";
            string nodeTag;

            var leader = await CreateRaftClusterAndGetLeader(groupSize, shouldRunInMemory : false, leaderIndex : 0, customSettings : new Dictionary <string, string>
            {
                [RavenConfiguration.GetKey(x => x.Cluster.MoveToRehabGraceTime)] = "4"
            });

            using (var leaderStore = new DocumentStore
            {
                Urls = new[] { leader.WebUrl },
                Database = databaseName
            })
            {
                leaderStore.Initialize();
                await CreateDatabaseInCluster(databaseName, groupSize, leader.WebUrl);

                var dbToplogy = (await leaderStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName))).Topology;
                Assert.Equal(groupSize, dbToplogy.Members.Count);

                var dataDir = Servers[1].Configuration.Core.DataDirectory.FullPath.Split('/').Last();
                nodeTag = Servers[1].ServerStore.NodeTag;
                // kill and change the url
                DisposeServerAndWaitForFinishOfDisposal(Servers[1]);
                var customSettings = new Dictionary <string, string>
                {
                    [RavenConfiguration.GetKey(x => x.Core.ServerUrls)] = newUrl,
                    [RavenConfiguration.GetKey(x => x.Security.UnsecuredAccessAllowed)] = UnsecuredAccessAddressRange.PublicNetwork.ToString()
                };
                Servers[1] = GetNewServer(new ServerCreationOptions
                {
                    CustomSettings = customSettings, RunInMemory = false, DeletePrevious = false, PartialPath = dataDir
                });
                newUrl = Servers[1].WebUrl;
                // ensure that at this point we still can't talk to node
                await Task.Delay(fromSeconds); // wait for the observer to update the status

                dbToplogy = (await leaderStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName))).Topology;
                Assert.Equal(1, dbToplogy.Rehabs.Count);
                Assert.Equal(groupSize - 1, dbToplogy.Members.Count);
            }

            await WaitForLeader(fromSeconds);

            leader = Servers.Single(s => s.Disposed == false && s.ServerStore.IsLeader());

            // remove and rejoin to change the url
            Assert.True(await leader.ServerStore.RemoveFromClusterAsync(nodeTag).WaitAsync(fromSeconds));
            Assert.True(await Servers[1].ServerStore.WaitForState(RachisState.Passive, CancellationToken.None).WaitAsync(fromSeconds));

            Assert.True(await leader.ServerStore.AddNodeToClusterAsync(Servers[1].ServerStore.GetNodeHttpServerUrl(), nodeTag).WaitAsync(fromSeconds));
            Assert.True(await Servers[1].ServerStore.WaitForState(RachisState.Follower, CancellationToken.None).WaitAsync(fromSeconds));

            Assert.Equal(3, WaitForValue(() => leader.ServerStore.GetClusterTopology().Members.Count, 3));

            // create a new database and verify that it resides on the server with the new url
            var(_, dbGroupNodes) = await CreateDatabaseInCluster(GetDatabaseName(), groupSize, leader.WebUrl);

            Assert.True(dbGroupNodes.Select(s => s.WebUrl).Contains(newUrl));
        }
        public async Task TwoWayExternalReplicationShouldNotLoadIdleDatabase()
        {
            using (var server = GetNewServer(new ServerCreationOptions
            {
                CustomSettings = new Dictionary <string, string>
                {
                    [RavenConfiguration.GetKey(x => x.Databases.MaxIdleTime)] = "10",
                    [RavenConfiguration.GetKey(x => x.Databases.FrequencyToCheckForIdle)] = "3",
                    [RavenConfiguration.GetKey(x => x.Core.RunInMemory)] = "false"
                }
            }))
                using (var store1 = GetDocumentStore(new Options
                {
                    Server = server,
                    RunInMemory = false
                }))
                    using (var store2 = GetDocumentStore(new Options
                    {
                        Server = server,
                        RunInMemory = false
                    }))
                    {
                        var externalTask1 = new ExternalReplication(store2.Database, "MyConnectionString1")
                        {
                            Name = "MyExternalReplication1"
                        };

                        var externalTask2 = new ExternalReplication(store1.Database, "MyConnectionString2")
                        {
                            Name = "MyExternalReplication2"
                        };
                        await AddWatcherToReplicationTopology(store1, externalTask1);
                        await AddWatcherToReplicationTopology(store2, externalTask2);

                        Assert.True(server.ServerStore.DatabasesLandlord.LastRecentlyUsed.TryGetValue(store1.Database, out _));
                        Assert.True(server.ServerStore.DatabasesLandlord.LastRecentlyUsed.TryGetValue(store2.Database, out _));

                        var now     = DateTime.Now;
                        var nextNow = now + TimeSpan.FromSeconds(60);
                        while (now < nextNow && server.ServerStore.IdleDatabases.Count < 2)
                        {
                            Thread.Sleep(3000);
                            now = DateTime.Now;
                        }
                        Assert.Equal(2, server.ServerStore.IdleDatabases.Count);

                        await store1.Maintenance.SendAsync(new CreateSampleDataOperation());

                        WaitForIndexing(store1);

                        var count          = 0;
                        var docs           = store1.Maintenance.Send(new GetStatisticsOperation()).CountOfDocuments;
                        var replicatedDocs = store2.Maintenance.Send(new GetStatisticsOperation()).CountOfDocuments;
                        while (docs != replicatedDocs && count < 20)
                        {
                            Thread.Sleep(3000);
                            replicatedDocs = store2.Maintenance.Send(new GetStatisticsOperation()).CountOfDocuments;
                            count++;
                        }
                        Assert.Equal(docs, replicatedDocs);

                        count   = 0;
                        nextNow = DateTime.Now + TimeSpan.FromMinutes(5);
                        while (server.ServerStore.IdleDatabases.Count == 0 && now < nextNow)
                        {
                            Thread.Sleep(500);
                            if (count % 10 == 0)
                            {
                                store1.Maintenance.Send(new GetStatisticsOperation());
                            }

                            now = DateTime.Now;
                            count++;
                        }
                        Assert.Equal(1, server.ServerStore.IdleDatabases.Count);

                        nextNow = DateTime.Now + TimeSpan.FromSeconds(15);
                        while (now < nextNow)
                        {
                            Thread.Sleep(2000);
                            store1.Maintenance.Send(new GetStatisticsOperation());
                            Assert.Equal(1, server.ServerStore.IdleDatabases.Count);
                            now = DateTime.Now;
                        }

                        nextNow = DateTime.Now + TimeSpan.FromMinutes(10);
                        while (now < nextNow && server.ServerStore.IdleDatabases.Count < 2)
                        {
                            Thread.Sleep(3000);
                            now = DateTime.Now;
                        }
                        Assert.Equal(2, server.ServerStore.IdleDatabases.Count);

                        using (var s = store2.OpenSession())
                        {
                            s.Advanced.RawQuery <dynamic>("from @all_docs")
                            .ToList();
                        }
                        Assert.Equal(1, server.ServerStore.IdleDatabases.Count);

                        var operation = await store2
                                        .Operations
                                        .ForDatabase(store2.Database)
                                        .SendAsync(new PatchByQueryOperation("from Companies update { this.Name = this.Name + '_patched'; }"));

                        await operation.WaitForCompletionAsync();

                        nextNow = DateTime.Now + TimeSpan.FromMinutes(2);
                        while (now < nextNow && server.ServerStore.IdleDatabases.Count > 0)
                        {
                            Thread.Sleep(5000);
                            now = DateTime.Now;
                        }
                        Assert.Equal(0, server.ServerStore.IdleDatabases.Count);

                        nextNow = DateTime.Now + TimeSpan.FromMinutes(10);
                        while (server.ServerStore.IdleDatabases.Count == 0 && now < nextNow)
                        {
                            Thread.Sleep(500);
                            if (count % 10 == 0)
                            {
                                store2.Maintenance.Send(new GetStatisticsOperation());
                            }

                            now = DateTime.Now;
                            count++;
                        }
                        Assert.Equal(1, server.ServerStore.IdleDatabases.Count);

                        nextNow = DateTime.Now + TimeSpan.FromSeconds(15);
                        while (now < nextNow)
                        {
                            Thread.Sleep(2000);
                            store2.Maintenance.Send(new GetStatisticsOperation());
                            Assert.Equal(1, server.ServerStore.IdleDatabases.Count);
                            now = DateTime.Now;
                        }
                    }
        }
예제 #23
0
        private void WriteDatabaseInfo(string databaseName, BlittableJsonReaderObject dbRecordBlittable,
                                       TransactionOperationContext context, AbstractBlittableJsonTextWriter writer)
        {
            try
            {
                var online = ServerStore.DatabasesLandlord.DatabasesCache.TryGetValue(databaseName, out Task <DocumentDatabase> dbTask) &&
                             dbTask != null &&
                             dbTask.IsCompleted;

                // Check for exceptions
                if (dbTask != null && dbTask.IsFaulted)
                {
                    var exception = dbTask.Exception.ExtractSingleInnerException();
                    WriteFaultedDatabaseInfo(databaseName, exception, context, writer);
                    return;
                }

                var dbRecord = JsonDeserializationCluster.DatabaseRecord(dbRecordBlittable);
                var db       = online ? dbTask.Result : null;

                var indexingStatus = db?.IndexStore?.Status ?? IndexRunningStatus.Running;
                // Looking for disabled indexing flag inside the database settings for offline database status
                if (dbRecord.Settings.TryGetValue(RavenConfiguration.GetKey(x => x.Indexing.Disabled), out var val) && bool.TryParse(val, out var indexingDisabled) && indexingDisabled)
                {
                    indexingStatus = IndexRunningStatus.Disabled;
                }

                var disabled        = dbRecord.Disabled;
                var topology        = dbRecord.Topology;
                var clusterTopology = ServerStore.GetClusterTopology(context);
                clusterTopology.ReplaceCurrentNodeUrlWithClientRequestedNodeUrlIfNecessary(ServerStore, HttpContext);

                var nodesTopology = new NodesTopology();

                var statuses = ServerStore.GetNodesStatuses();
                if (topology != null)
                {
                    foreach (var member in topology.Members)
                    {
                        var url  = clusterTopology.GetUrlFromTag(member);
                        var node = new InternalReplication
                        {
                            Database = databaseName,
                            NodeTag  = member,
                            Url      = url
                        };
                        nodesTopology.Members.Add(GetNodeId(node));
                        SetNodeStatus(topology, member, nodesTopology, statuses);
                    }

                    foreach (var promotable in topology.Promotables)
                    {
                        topology.PredefinedMentors.TryGetValue(promotable, out var mentorCandidate);
                        var node   = GetNode(databaseName, clusterTopology, promotable, mentorCandidate, out var promotableTask);
                        var mentor = topology.WhoseTaskIsIt(ServerStore.Engine.CurrentState, promotableTask, null);
                        nodesTopology.Promotables.Add(GetNodeId(node, mentor));
                        SetNodeStatus(topology, promotable, nodesTopology, statuses);
                    }

                    foreach (var rehab in topology.Rehabs)
                    {
                        var node   = GetNode(databaseName, clusterTopology, rehab, null, out var promotableTask);
                        var mentor = topology.WhoseTaskIsIt(ServerStore.Engine.CurrentState, promotableTask, null);
                        nodesTopology.Rehabs.Add(GetNodeId(node, mentor));
                        SetNodeStatus(topology, rehab, nodesTopology, statuses);
                    }
                }

                if (online == false)
                {
                    // if state of database is found in the cache we can continue
                    if (ServerStore.DatabaseInfoCache.TryGet(databaseName, databaseInfoJson =>
                    {
                        databaseInfoJson.Modifications = new DynamicJsonValue(databaseInfoJson)
                        {
                            [nameof(DatabaseInfo.Disabled)] = disabled,
                            [nameof(DatabaseInfo.IndexingStatus)] = indexingStatus.ToString(),
                            [nameof(DatabaseInfo.NodesTopology)] = nodesTopology.ToJson(),
                            [nameof(DatabaseInfo.DeletionInProgress)] = DynamicJsonValue.Convert(dbRecord.DeletionInProgress)
                        };

                        context.Write(writer, databaseInfoJson);
                    }))
                    {
                        return;
                    }

                    // we won't find it if it is a new database or after a dirty shutdown,
                    // so just report empty values then
                }

                var size = db?.GetSizeOnDisk() ?? (new Size(0), new Size(0));

                var databaseInfo = new DatabaseInfo
                {
                    Name            = databaseName,
                    Disabled        = disabled,
                    TotalSize       = size.Data,
                    TempBuffersSize = size.TempBuffers,

                    IsAdmin     = true,
                    IsEncrypted = dbRecord.Encrypted,
                    UpTime      = online ? (TimeSpan?)GetUptime(db) : null,
                    BackupInfo  = GetBackupInfo(db),

                    Alerts         = db?.NotificationCenter.GetAlertCount() ?? 0,
                    RejectClients  = false,
                    LoadError      = null,
                    IndexingErrors = db?.IndexStore?.GetIndexes()?.Sum(index => index.GetErrorCount()) ?? 0,

                    DocumentsCount             = db?.DocumentsStorage.GetNumberOfDocuments() ?? 0,
                    HasRevisionsConfiguration  = db?.DocumentsStorage.RevisionsStorage.Configuration != null,
                    HasExpirationConfiguration = db?.ExpiredDocumentsCleaner != null,
                    IndexesCount   = db?.IndexStore?.GetIndexes()?.Count() ?? 0,
                    IndexingStatus = indexingStatus,

                    NodesTopology            = nodesTopology,
                    ReplicationFactor        = topology?.ReplicationFactor ?? -1,
                    DynamicNodesDistribution = topology?.DynamicNodesDistribution ?? false,
                    DeletionInProgress       = dbRecord.DeletionInProgress
                };

                var doc = databaseInfo.ToJson();
                context.Write(writer, doc);
            }
            catch (Exception e)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Failed to get database info for: {databaseName}", e);
                }

                WriteFaultedDatabaseInfo(databaseName, e, context, writer);
            }
        }
예제 #24
0
        public void CertificateAndMasterKeyExecTest()
        {
            string script;
            IDictionary <string, string> customSettings = new ConcurrentDictionary <string, string>();
            var keyPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
            var buffer  = new byte[256 / 8];

            using (var cryptoRandom = new RNGCryptoServiceProvider())
            {
                cryptoRandom.GetBytes(buffer);
            }
            File.WriteAllBytes(keyPath, buffer);
            var certPath = GenerateAndSaveSelfSignedCertificate();

            if (PlatformDetails.RunningOnPosix)
            {
                var scriptPath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Guid.NewGuid().ToString(), ".sh"));
                var keyArgs    = CommandLineArgumentEscaper.EscapeAndConcatenate(new List <string> {
                    scriptPath, keyPath
                });
                var certArgs = CommandLineArgumentEscaper.EscapeAndConcatenate(new List <string> {
                    scriptPath, certPath.ServerCertificatePath
                });

                customSettings[RavenConfiguration.GetKey(x => x.Security.MasterKeyExec)]                = "bash";
                customSettings[RavenConfiguration.GetKey(x => x.Security.MasterKeyExecArguments)]       = $"{keyArgs}";
                customSettings[RavenConfiguration.GetKey(x => x.Security.CertificateLoadExec)]          = "bash";
                customSettings[RavenConfiguration.GetKey(x => x.Security.CertificateLoadExecArguments)] = $"{certArgs}";
                customSettings[RavenConfiguration.GetKey(x => x.Core.ServerUrls)] = "https://" + Environment.MachineName + ":0";

                script = "#!/bin/bash\ncat \"$1\"";
                File.WriteAllText(scriptPath, script);
                Process.Start("chmod", $"700 {scriptPath}");
            }
            else
            {
                var scriptPath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Guid.NewGuid().ToString(), ".ps1"));
                var keyArgs    = CommandLineArgumentEscaper.EscapeAndConcatenate(new List <string> {
                    "-NoProfile", scriptPath, keyPath
                });
                var certArgs = CommandLineArgumentEscaper.EscapeAndConcatenate(new List <string> {
                    "-NoProfile", scriptPath, certPath.ServerCertificatePath
                });

                customSettings[RavenConfiguration.GetKey(x => x.Security.MasterKeyExec)]                = "powershell";
                customSettings[RavenConfiguration.GetKey(x => x.Security.MasterKeyExecArguments)]       = $"{keyArgs}";
                customSettings[RavenConfiguration.GetKey(x => x.Security.CertificateLoadExec)]          = "powershell";
                customSettings[RavenConfiguration.GetKey(x => x.Security.CertificateRenewExec)]         = "powershell";
                customSettings[RavenConfiguration.GetKey(x => x.Security.CertificateChangeExec)]        = "powershell";
                customSettings[RavenConfiguration.GetKey(x => x.Security.CertificateLoadExecArguments)] = $"{certArgs}";
                customSettings[RavenConfiguration.GetKey(x => x.Core.ServerUrls)] = "https://" + Environment.MachineName + ":0";
                script = @"param([string]$userArg)
try {
    $bytes = Get-Content -path $userArg -encoding Byte
    $stdout = [System.Console]::OpenStandardOutput()
    $stdout.Write($bytes, 0, $bytes.Length)
}
catch {
    Write-Error $_.Exception
    exit 1
}
exit 0";
                File.WriteAllText(scriptPath, script);
            }

            UseNewLocalServer(customSettings: customSettings, runInMemory: false);
            // The master key loading is lazy, let's put a database secret key to invoke it.
            var dbName      = GetDatabaseName();
            var databaseKey = new byte[32];

            using (var rand = RandomNumberGenerator.Create())
            {
                rand.GetBytes(databaseKey);
            }
            var base64Key = Convert.ToBase64String(databaseKey);

            // sometimes when using `dotnet xunit` we get platform not supported from ProtectedData
            try
            {
                ProtectedData.Protect(Encoding.UTF8.GetBytes("Is supported?"), null, DataProtectionScope.CurrentUser);
            }
            catch (PlatformNotSupportedException)
            {
                return;
            }
            Server.ServerStore.PutSecretKey(base64Key, dbName, true);
            X509Certificate2 serverCertificate;

            try
            {
                serverCertificate = new X509Certificate2(certPath.ServerCertificatePath, (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
            }
            catch (CryptographicException e)
            {
                throw new CryptographicException($"Failed to load the test certificate from {certPath}.", e);
            }
            using (var store = GetDocumentStore(new Options
            {
                AdminCertificate = serverCertificate,
                ClientCertificate = serverCertificate,
                ModifyDatabaseName = s => dbName,
                ModifyDatabaseRecord = record => record.Encrypted = true,
                Path = NewDataPath()
            }))
            {
            }
            var secrets         = Server.ServerStore.Secrets;
            var serverMasterKey = (Lazy <byte[]>) typeof(SecretProtection).GetField("_serverMasterKey", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(secrets);

            Assert.True(serverMasterKey.Value.SequenceEqual(buffer));
            Assert.True(Server.Certificate.Certificate.Equals(serverCertificate));
        }
예제 #25
0
        public async Task ClusterTransactionRequestWithRevisions()
        {
            var leader = await CreateRaftClusterAndGetLeader(5, shouldRunInMemory : false, leaderIndex : 0);

            using (var leaderStore = GetDocumentStore(new Options
            {
                DeleteDatabaseOnDispose = false,
                Server = leader,
                ReplicationFactor = 5,
                ModifyDocumentStore = (store) => store.Conventions.DisableTopologyUpdates = true
            }))
            {
                var user1 = new User()
                {
                    Name = "Karmel"
                };
                var user3 = new User()
                {
                    Name = "Indych"
                };
                var index = await RevisionsHelper.SetupRevisions(leader.ServerStore, leaderStore.Database, configuration => configuration.Collections["Users"].PurgeOnDelete = false);
                await WaitForRaftIndexToBeAppliedInCluster(index, TimeSpan.FromSeconds(15));

                // bring our SUT node down, but we still have a cluster and can execute cluster transaction.
                var server  = Servers[1];
                var url     = server.WebUrl;
                var dataDir = Servers[1].Configuration.Core.DataDirectory.FullPath.Split('/').Last();

                await DisposeServerAndWaitForFinishOfDisposalAsync(server);

                using (var session = leaderStore.OpenAsyncSession(new SessionOptions
                {
                    TransactionMode = TransactionMode.ClusterWide
                }))
                {
                    Assert.Equal(1, session.Advanced.RequestExecutor.TopologyNodes.Count);
                    Assert.Equal(leader.WebUrl, session.Advanced.RequestExecutor.Url);
                    session.Advanced.ClusterTransaction.CreateCompareExchangeValue("usernames/ayende", user1);
                    await session.StoreAsync(user3, "foo/bar");

                    await session.SaveChangesAsync();

                    var user = (await session.Advanced.ClusterTransaction.GetCompareExchangeValueAsync <User>("usernames/ayende")).Value;
                    Assert.Equal(user1.Name, user.Name);
                    user = await session.LoadAsync <User>("foo/bar");

                    Assert.Equal(user3.Name, user.Name);

                    var list = await session.Advanced.Revisions.GetForAsync <User>(user.Id);

                    Assert.Equal(1, list.Count);
                    var changeVector = session.Advanced.GetChangeVectorFor(user);
                    Assert.NotNull(await session.Advanced.Revisions.GetAsync <User>(changeVector));
                }
                // bring more nodes down, so only one node is left
                var dataDir2 = Servers[2].Configuration.Core.DataDirectory.FullPath.Split('/').Last();
                var url2     = Servers[2].WebUrl;
                var task1    = DisposeServerAndWaitForFinishOfDisposalAsync(Servers[2]);
                var task2    = DisposeServerAndWaitForFinishOfDisposalAsync(Servers[3]);
                var task3    = DisposeServerAndWaitForFinishOfDisposalAsync(Servers[4]);
                await Task.WhenAll(task1, task2, task3);

                using (var session = leaderStore.OpenAsyncSession())
                {
                    Assert.Equal(leader.WebUrl, session.Advanced.RequestExecutor.Url);
                    await session.StoreAsync(user1, "foo/bar");

                    await session.SaveChangesAsync();

                    var list = await session.Advanced.Revisions.GetForAsync <User>(user1.Id);

                    Assert.Equal(2, list.Count);
                }

                long lastRaftIndex;
                using (leader.ServerStore.Engine.ContextPool.AllocateOperationContext(out TransactionOperationContext ctx))
                    using (ctx.OpenReadTransaction())
                    {
                        lastRaftIndex = leader.ServerStore.Engine.GetLastCommitIndex(ctx);
                    }

                // revive the SUT node
                var revived = Servers[1] = GetNewServer(new Dictionary <string, string>
                {
                    [RavenConfiguration.GetKey(x => x.Core.ServerUrls)]         = url,
                    [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)] = "400"
                }, runInMemory: false, deletePrevious: false, partialPath: dataDir);
                using (var revivedStore = new DocumentStore()
                {
                    Urls = new[] { revived.WebUrl },
                    Database = leaderStore.Database,
                    Conventions = new DocumentConventions
                    {
                        DisableTopologyUpdates = true
                    }
                }.Initialize())
                {
                    // let the document with the revision to replicate
                    Assert.True(WaitForDocument(revivedStore, "foo/bar"));
                    using (var session = revivedStore.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("foo/bar");

                        var changeVector = session.Advanced.GetChangeVectorFor(user);
                        Assert.NotNull(await session.Advanced.Revisions.GetAsync <User>(changeVector));
                        var list = await session.Advanced.Revisions.GetForAsync <User>("foo/bar");

                        Assert.Equal(2, list.Count);

                        // revive another node so we should have a functional cluster now
                        Servers[2] = GetNewServer(new Dictionary <string, string>
                        {
                            [RavenConfiguration.GetKey(x => x.Core.ServerUrls)]         = url2,
                            [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)] = "400"
                        }, runInMemory: false, deletePrevious: false, partialPath: dataDir2);

                        // wait for the log to apply on the SUT node
                        using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15)))
                        {
                            await leader.ServerStore.Engine.WaitForLeaveState(RachisState.Candidate, cts.Token);
                        }
                        var database = await Servers[1].ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(leaderStore.Database);
                        await database.RachisLogIndexNotifications.WaitForIndexNotification(lastRaftIndex, TimeSpan.FromSeconds(15));

                        list = await session.Advanced.Revisions.GetForAsync <User>("foo/bar");

                        Assert.Equal(2, list.Count);
                    }
                }
            }
        }
예제 #26
0
        public async Task OnDirectoryInitializeInMemoryTest()
        {
            string script;
            IDictionary <string, string> customSettings = new ConcurrentDictionary <string, string>();

            var scriptFile = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Guid.NewGuid().ToString(), ".ps1"));
            var outputFile = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Guid.NewGuid().ToString(), ".txt"));

            if (PlatformDetails.RunningOnPosix)
            {
                customSettings[RavenConfiguration.GetKey(x => x.Storage.OnDirectoryInitializeExec)]          = "bash";
                customSettings[RavenConfiguration.GetKey(x => x.Storage.OnDirectoryInitializeExecArguments)] = $"{scriptFile} {outputFile}";

                script = "#!/bin/bash\r\necho \"$2 $3 $4 $5 $6\" >> $1";
                File.WriteAllText(scriptFile, script);
                Process.Start("chmod", $"700 {scriptFile}");
            }
            else
            {
                customSettings[RavenConfiguration.GetKey(x => x.Storage.OnDirectoryInitializeExec)]          = "powershell";
                customSettings[RavenConfiguration.GetKey(x => x.Storage.OnDirectoryInitializeExecArguments)] = $"{scriptFile} {outputFile}";

                script = @"
param([string]$userArg ,[string]$type, [string]$name, [string]$dataPath, [string]$tempPath, [string]$journalPath)
Add-Content $userArg ""$type $name $dataPath $tempPath $journalPath\r\n""
exit 0";
                File.WriteAllText(scriptFile, script);
            }

            UseNewLocalServer(customSettings: customSettings);

            // Creating dummy storage env options, so we can tell all the different paths
            using (var options = StorageEnvironmentOptions.CreateMemoryOnly())
            {
                using (var store = GetDocumentStore())
                {
                    store.Maintenance.Send(new CreateSampleDataOperation());

                    // the database loads after all indexes are loaded
                    var documentDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);

                    var lines = File.ReadAllLines(outputFile);
                    Assert.True(lines.Length == 6);
                    Assert.True(lines[0].Contains($"{DirectoryExecUtils.EnvironmentType.System} {SystemDbName} {options.BasePath} {options.TempPath} {options.JournalPath}"));
                    Assert.True(lines[1].Contains($"{DirectoryExecUtils.EnvironmentType.Configuration} {store.Database} {options.BasePath} {options.TempPath} {options.JournalPath}"));
                    Assert.True(lines[2].Contains($"{DirectoryExecUtils.EnvironmentType.Database} {store.Database} {options.BasePath} {options.TempPath} {options.JournalPath}"));

                    var indexes = documentDatabase.IndexStore.GetIndexes().ToArray();

                    Assert.True(indexes.Length == 3);

                    // The indexes order in the IndexStore don't match the order of storage env creation and we need a one-to-one match.
                    var matches = lines.ToList().GetRange(3, 3);

                    foreach (var index in indexes)
                    {
                        var expected      = $"{DirectoryExecUtils.EnvironmentType.Index} {store.Database} {index._environment.Options.BasePath} {index._environment.Options.TempPath} {index._environment.Options.JournalPath}";
                        var indexToRemove = matches.FindIndex(str => str.Contains(expected));
                        if (indexToRemove != -1)
                        {
                            matches.RemoveAt(indexToRemove);
                        }
                    }

                    Assert.Equal(0, matches.Count);
                }
            }
        }
예제 #27
0
        protected DocumentStore GetDocumentStore(Options options = null, [CallerMemberName] string caller = null)
        {
            try
            {
                lock (_getDocumentStoreSync)
                {
                    options = options ?? Options.Default;
                    var serverToUse = options.Server ?? Server;

                    var name = GetDatabaseName(caller);

                    if (options.ModifyDatabaseName != null)
                    {
                        name = options.ModifyDatabaseName(name) ?? name;
                    }

                    var hardDelete  = true;
                    var runInMemory = true;

                    var pathToUse = options.Path;
                    if (pathToUse == null)
                    {
                        pathToUse = NewDataPath(name);
                    }
                    else
                    {
                        hardDelete  = false;
                        runInMemory = false;
                    }

                    var doc = new DatabaseRecord(name)
                    {
                        Settings =
                        {
                            [RavenConfiguration.GetKey(x => x.Replication.ReplicationMinimalHeartbeat)] = "1",
                            [RavenConfiguration.GetKey(x => x.Replication.RetryReplicateAfter)]         = "1",
                            [RavenConfiguration.GetKey(x => x.Core.RunInMemory)]   = runInMemory.ToString(),
                            [RavenConfiguration.GetKey(x => x.Core.DataDirectory)] = pathToUse,
                            [RavenConfiguration.GetKey(x => x.Core.ThrowIfAnyIndexCannotBeOpened)] = "true",
                            [RavenConfiguration.GetKey(x => x.Indexing.MinNumberOfMapAttemptsAfterWhichBatchWillBeCanceledIfRunningLowOnMemory)] = int.MaxValue.ToString()
                        }
                    };

                    options.ModifyDatabaseRecord?.Invoke(doc);

                    var store = new DocumentStore
                    {
                        Urls        = UseFiddler(serverToUse.WebUrl),
                        Database    = name,
                        Certificate = options.ClientCertificate
                    };

                    options.ModifyDocumentStore?.Invoke(store);

                    //This gives too much error details in most cases, we don't need this now
                    store.RequestExecutorCreated += (sender, executor) =>
                    {
                        executor.AdditionalErrorInformation += sb => sb.AppendLine().Append(GetLastStatesFromAllServersOrderedByTime());
                    };

                    store.Initialize();

                    if (options.CreateDatabase)
                    {
                        foreach (var server in Servers)
                        {
                            using (server.ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
                            {
                                context.OpenReadTransaction();
                                if (server.ServerStore.Cluster.Read(context, Constants.Documents.Prefix + name) != null)
                                {
                                    throw new InvalidOperationException($"Database '{name}' already exists");
                                }
                            }
                        }

                        DatabasePutResult result;

                        if (options.AdminCertificate != null)
                        {
                            using (var adminStore = new DocumentStore
                            {
                                Urls = UseFiddler(serverToUse.WebUrl),
                                Database = name,
                                Certificate = options.AdminCertificate
                            }.Initialize())
                            {
                                result = adminStore.Maintenance.Server.Send(new CreateDatabaseOperation(doc, options.ReplicationFactor));
                            }
                        }
                        else
                        {
                            result = store.Maintenance.Server.Send(new CreateDatabaseOperation(doc, options.ReplicationFactor));
                        }

                        Assert.True(result.RaftCommandIndex > 0); //sanity check
                        store.Urls = result.NodesAddedTo.SelectMany(UseFiddler).ToArray();
                        var timeout = TimeSpan.FromMinutes(Debugger.IsAttached ? 5 : 1);
                        var task    = WaitForRaftIndexToBeAppliedInCluster(result.RaftCommandIndex, timeout);
                        task.ConfigureAwait(false).GetAwaiter().GetResult();
                    }

                    store.BeforeDispose += (sender, args) =>
                    {
                        if (CreatedStores.TryRemove(store) == false)
                        {
                            return; // can happen if we are wrapping the store inside sharded one
                        }
                        foreach (var server in Servers)
                        {
                            if (server.Disposed)
                            {
                                continue;
                            }
                            var serverUrl = UseFiddler(server.WebUrl);
                            if (store.Urls.Any(url => serverUrl.Contains(url)) == false)
                            {
                                continue;
                            }

                            try
                            {
                                var databaseTask = server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(name, options.IgnoreDisabledDatabase);
                                if (databaseTask != null && databaseTask.IsCompleted == false)
                                {
                                    // if we are disposing store before database had chance to load then we need to wait
                                    databaseTask.Wait();
                                }
                            }
                            catch (DatabaseDisabledException)
                            {
                                continue;
                            }
                            catch (DatabaseNotRelevantException)
                            {
                                continue;
                            }

                            if (options.DeleteDatabaseOnDispose)
                            {
                                DeleteDatabaseResult result;
                                try
                                {
                                    if (options.AdminCertificate != null)
                                    {
                                        using (var adminStore = new DocumentStore
                                        {
                                            Urls = UseFiddler(serverToUse.WebUrl),
                                            Database = name,
                                            Certificate = options.AdminCertificate
                                        }.Initialize())
                                        {
                                            result = adminStore.Maintenance.Server.Send(new DeleteDatabasesOperation(name, hardDelete));
                                        }
                                    }
                                    else
                                    {
                                        result = store.Maintenance.Server.Send(new DeleteDatabasesOperation(name, hardDelete));
                                    }
                                }
                                catch (DatabaseDoesNotExistException)
                                {
                                    continue;
                                }
                                catch (NoLeaderException)
                                {
                                    continue;
                                }

                                server.ServerStore.Cluster.WaitForIndexNotification(result.RaftCommandIndex).ConfigureAwait(false).GetAwaiter().GetResult();
                            }
                        }
                    };
                    CreatedStores.Add(store);

                    return(store);
                }
            }
            catch (TimeoutException te)
            {
                throw new TimeoutException($"{te.Message} {Environment.NewLine} {te.StackTrace}{Environment.NewLine}Servers states:{Environment.NewLine}{GetLastStatesFromAllServersOrderedByTime()}");
            }
        }
예제 #28
0
        public async Task RequiredForNextPolicyTest()
        {
            DefaultClusterSettings[RavenConfiguration.GetKey(x => x.Tombstones.CleanupInterval)] = 1.ToString();
            var cluster = await CreateRaftCluster(3, watcherCluster : true);

            using (var store = GetDocumentStore(new Options {
                Server = cluster.Leader, ReplicationFactor = 3, RunInMemory = false
            }))
            {
                var retention = TimeSpan.FromSeconds(180);
                var raw       = new RawTimeSeriesPolicy(retention);
                var config    = new TimeSeriesConfiguration
                {
                    Collections = new Dictionary <string, TimeSeriesCollectionConfiguration>
                    {
                        ["Users"] = new TimeSeriesCollectionConfiguration
                        {
                            RawPolicy = raw,
                            Policies  = new List <TimeSeriesPolicy> {
                                new TimeSeriesPolicy("ByMinute", TimeSpan.FromSeconds(60))
                            }
                        }
                    },
                    PolicyCheckFrequency = TimeSpan.FromSeconds(1)
                };
                await store.Maintenance.SendAsync(new ConfigureTimeSeriesOperation(config));

                var now = new DateTime(2021, 6, 1, 18, 45, 0, 999, DateTimeKind.Utc);
                foreach (var server in Servers)
                {
                    var database = await server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);

                    database.Time.UtcDateTime = () => now;
                }

                var baseline = now.AddSeconds(-120);
                using (var session = store.OpenSession())
                {
                    var id = "users/karmel/0";
                    session.Store(new User {
                        Name = "Karmel"
                    }, id);
                    for (int i = 0; i < 120; i++)
                    {
                        session.TimeSeriesFor(id, "Heartrate")
                        .Append(baseline.AddSeconds(i), i);
                    }

                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                {
                    session.Store(new User(), "marker");
                    session.SaveChanges();
                    Assert.True(await WaitForDocumentInClusterAsync <User>(cluster.Nodes, store.Database, "marker", null, TimeSpan.FromSeconds(15)));
                }

                foreach (var server in Servers)
                {
                    var database = await server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);

                    database.Time.UtcDateTime = () => now.AddMinutes(3);
                }

                var sp    = Stopwatch.StartNew();
                var check = true;
                while (check)
                {
                    Assert.True(sp.Elapsed < retention.Add(TimeSpan.FromMinutes(-2)), $"too long has passed {sp.Elapsed}, retention is {retention}");
                    await Task.Delay(200);

                    check = false;
                    foreach (var server in Servers)
                    {
                        var database = await server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);

                        var tss = database.DocumentsStorage.TimeSeriesStorage;

                        using (database.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx))
                            using (ctx.OpenReadTransaction())
                            {
                                var id    = $"users/karmel/0";
                                var stats = tss.Stats.GetStats(ctx, id, "Heartrate");

                                TimeSeriesReader reader;
                                if (stats == default || stats.Count == 0)
                                {
                                    var name = config.Collections["Users"].Policies[0].GetTimeSeriesName("Heartrate");
                                    stats  = tss.Stats.GetStats(ctx, id, name);
                                    reader = tss.GetReader(ctx, id, name, DateTime.MinValue, DateTime.MaxValue);

                                    Assert.True(stats.Count > 0);
                                    Assert.Equal(stats.Start, reader.First().Timestamp, RavenTestHelper.DateTimeComparer.Instance);
                                    Assert.Equal(stats.End, reader.Last().Timestamp, RavenTestHelper.DateTimeComparer.Instance);
                                    continue;
                                }
                                check  = true;
                                reader = tss.GetReader(ctx, id, "Heartrate", DateTime.MinValue, DateTime.MaxValue);
                                Assert.Equal(stats.Start, reader.First().Timestamp, RavenTestHelper.DateTimeComparer.Instance);
                                Assert.Equal(stats.End, reader.Last().Timestamp, RavenTestHelper.DateTimeComparer.Instance);
                            }
                    }
                }
            }
        }
예제 #29
0
        private void ValidateAllowedDestinations()
        {
            if (AllowedDestinations == null)
            {
                return;
            }

            if (AllowedDestinations.Contains("None", StringComparer.OrdinalIgnoreCase))
            {
                if (AllowedDestinations.Length > 1)
                {
                    throw new ArgumentException($"If you specify \"None\" under '{RavenConfiguration.GetKey(x => x.Backup.AllowedDestinations)}' then it must be the only value.");
                }

                return;
            }

            foreach (var dest in AllowedDestinations)
            {
                if (_allDestinations.Contains(dest, StringComparer.OrdinalIgnoreCase))
                {
                    continue;
                }
                throw new ArgumentException($"The destination '{dest}' defined in the configuration under '{RavenConfiguration.GetKey(x => x.Backup.AllowedDestinations)}' is unknown. Make sure to use the following destinations: {string.Join(", ", _allDestinations)}.");
            }
        }
예제 #30
0
        public async Task AwaitAsyncPatchByIndexShouldWork()
        {
            using (var store = GetDocumentStore(modifyDatabaseDocument: document => document.Settings[RavenConfiguration.GetKey(x => x.Core.RunInMemory)] = "false"))
            {
                RavenQueryStatistics stats;
                using (var session = store.OpenSession())
                {
                    session.Query <User>()
                    .Statistics(out stats)
                    .Where(x => x.Name == "John")
                    .ToList();
                }

                using (var session = store.OpenAsyncSession())
                {
                    for (int i = 0; i < 30; i++)
                    {
                        await session.StoreAsync(new User
                        {
                            Name     = "First #" + i,
                            LastName = "Last #" + i
                        }, "users/" + i);

                        await session.SaveChangesAsync();
                    }
                }

                WaitForIndexing(store, timeout: TimeSpan.FromMinutes(5));

                JsonOperationContext context;
                store.GetRequestExecuter(store.DefaultDatabase).ContextPool.AllocateOperationContext(out context);

                var patchByIndexOperation = new PatchByIndexOperation(context);
                var patchCommand          = patchByIndexOperation.CreateRequest(stats.IndexName,
                                                                                new IndexQuery {
                    Query = string.Empty
                },
                                                                                null, new PatchRequest {
                    Script = "this.FullName = this.FirstName + ' ' + this.LastName;"
                }, store);
                if (patchCommand != null)
                {
                    await store.GetRequestExecuter(store.DefaultDatabase).ExecuteAsync(patchCommand, context);
                }

                using (var db = store.OpenAsyncSession())
                {
                    var lastUser = await db.LoadAsync <User>("users/29");

                    Assert.NotNull(lastUser.FullName);
                }
            }
        }