Example #1
0
        public async Task UnregisterHubAccess()
        {
            var hub        = GetStringQueryString("name", true);
            var thumbprint = GetStringQueryString("thumbprint", true);

            if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false)
            {
                throw new BadRequestException(errorMessage);
            }

            ServerStore.LicenseManager.AssertCanAddPullReplicationAsHub();

            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
            {
                var command = new UnregisterReplicationHubAccessCommand(Database.Name, hub, thumbprint, GetRaftRequestIdFromQuery());
                var result  = await Server.ServerStore.SendToLeaderAsync(command);
                await WaitForIndexToBeApplied(context, result.Index);

                await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    writer.WriteStartObject();
                    writer.WritePropertyName(nameof(ReplicationHubAccessResponse.RaftCommandIndex));
                    writer.WriteInteger(result.Index);
                    writer.WriteEndObject();
                }
            }
        }
 public ModifyConflictSolverOperation(string database, Dictionary <string, ScriptResolver> collectionByScript = null, bool resolveToLatest = false)
 {
     ResourceNameValidator.AssertValidDatabaseName(database);
     _database          = database;
     CollectionByScript = collectionByScript;
     ResolveToLatest    = resolveToLatest;
 }
Example #3
0
        public async Task DefineHub()
        {
            if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false)
            {
                throw new BadRequestException(errorMessage);
            }

            ServerStore.LicenseManager.AssertCanAddPullReplicationAsHub();

            PullReplicationDefinition pullReplication = null;

            await DatabaseConfigurations((_, databaseName, blittableJson, guid) =>
            {
                pullReplication = JsonDeserializationClient.PullReplicationDefinition(blittableJson);

                pullReplication.Validate(ServerStore.Server.Certificate?.Certificate != null);
                var updatePullReplication = new UpdatePullReplicationAsHubCommand(databaseName, guid)
                {
                    Definition = pullReplication
                };
                return(ServerStore.SendToLeaderAsync(updatePullReplication));
            }, "update-hub-pull-replication",
                                         GetRaftRequestIdFromQuery(),
                                         fillJson : (json, _, index) =>
            {
                json[nameof(OngoingTask.TaskId)] = pullReplication.TaskId == 0 ? index : pullReplication.TaskId;
            }, statusCode : HttpStatusCode.Created);
        }
Example #4
0
        public async Task UpdatePullReplicationOnSinkNode()
        {
            if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false)
            {
                throw new BadRequestException(errorMessage);
            }

            ServerStore.LicenseManager.AssertCanAddPullReplicationAsSink();

            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
            {
                PullReplicationAsSink pullReplication = null;
                await DatabaseConfigurations(
                    (_, databaseName, blittableJson, guid) => ServerStore.UpdatePullReplicationAsSink(databaseName, blittableJson, guid, out pullReplication),
                    "update-sink-pull-replication", GetRaftRequestIdFromQuery(),
                    fillJson : (json, _, index) =>
                {
                    using (context.OpenReadTransaction())
                    {
                        var topology = ServerStore.Cluster.ReadDatabaseTopology(context, Database.Name);
                        json[nameof(OngoingTask.ResponsibleNode)] = Database.WhoseTaskIsIt(topology, pullReplication, null);
                    }

                    json[nameof(ModifyOngoingTaskResult.TaskId)] = pullReplication.TaskId == 0 ? index : pullReplication.TaskId;
                }, statusCode : HttpStatusCode.Created);
            }
        }
Example #5
0
        private static void ValidatePermissions(CertificateDefinition certificate, ServerStore serverStore)
        {
            if (certificate.Permissions == null)
            {
                throw new ArgumentException($"{nameof(certificate.Permissions)} is a required field in the certificate definition");
            }

            foreach (var kvp in certificate.Permissions)
            {
                if (string.IsNullOrWhiteSpace(kvp.Key))
                {
                    throw new ArgumentException("Error in permissions in the certificate definition, database name is empty");
                }

                if (ResourceNameValidator.IsValidResourceName(kvp.Key, serverStore.Configuration.Core.DataDirectory.FullPath, out var errorMessage) == false)
                {
                    throw new ArgumentException("Error in permissions in the certificate definition:" + errorMessage);
                }

                if (kvp.Value != DatabaseAccess.ReadWrite && kvp.Value != DatabaseAccess.Admin)
                {
                    throw new ArgumentException($"Error in permissions in the certificate definition, invalid access {kvp.Value} for database {kvp.Key}");
                }
            }
        }
        protected async Task DatabaseConfigurations(SetupFunc setupConfigurationFunc,
                                                    string debug,
                                                    string raftRequestId,
                                                    RefAction beforeSetupConfiguration = null,
                                                    Action <DynamicJsonValue, BlittableJsonReaderObject, long> fillJson = null,
                                                    HttpStatusCode statusCode = HttpStatusCode.OK)
        {
            if (TryGetAllowedDbs(Database.Name, out var _, requireAdmin: true) == false)
            {
                return;
            }

            if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false)
            {
                throw new BadRequestException(errorMessage);
            }

            ServerStore.EnsureNotPassive();
            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
            {
                var configurationJson = await context.ReadForMemoryAsync(RequestBodyStream(), debug);

                beforeSetupConfiguration?.Invoke(Database.Name, ref configurationJson, context);

                var(index, _) = await setupConfigurationFunc(context, Database.Name, configurationJson, raftRequestId);

                DatabaseTopology dbTopology;
                using (context.OpenReadTransaction())
                {
                    dbTopology = ServerStore.Cluster.ReadDatabaseTopology(context, Database.Name);
                }

                if (dbTopology.RelevantFor(ServerStore.NodeTag))
                {
                    var db = await ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(Database.Name);

                    await db.RachisLogIndexNotifications.WaitForIndexNotification(index, ServerStore.Engine.OperationTimeout);
                }
                else
                {
                    await ServerStore.Cluster.WaitForIndexNotification(index);
                }
                HttpContext.Response.StatusCode = (int)statusCode;

                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    var json = new DynamicJsonValue
                    {
                        ["RaftCommandIndex"] = index,
                    };
                    fillJson?.Invoke(json, configurationJson, index);
                    context.Write(writer, json);
                    writer.Flush();
                }
            }
        }
Example #7
0
        public async Task RegisterHubAccess()
        {
            var hubTaskName = GetStringQueryString("name", true);

            if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false)
            {
                throw new BadRequestException(errorMessage);
            }

            ServerStore.LicenseManager.AssertCanAddPullReplicationAsHub();

            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
            {
                PullReplicationDefinition hubDefinition;

                using (context.OpenReadTransaction())
                {
                    hubDefinition = Server.ServerStore.Cluster.ReadPullReplicationDefinition(Database.Name, hubTaskName, context);
                    if (hubDefinition == null)
                    {
                        HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                        return;
                    }
                }

#pragma warning disable CS0618 // Type or member is obsolete
                if (hubDefinition.Certificates != null && hubDefinition.Certificates.Count > 0)
#pragma warning restore CS0618 // Type or member is obsolete
                {
                    // handle backward compatibility
                    throw new InvalidOperationException("Cannot register hub access to a replication hub that already has inline certificates: " + hubTaskName +
                                                        ". Create a new replication hub and try again");
                }

                var blittableJson = await context.ReadForMemoryAsync(RequestBodyStream(), "register-hub-access");

                var access = JsonDeserializationClient.ReplicationHubAccess(blittableJson);
                access.Validate(hubDefinition.WithFiltering);

                using var cert = new X509Certificate2(Convert.FromBase64String(access.CertificateBase64));

                var command = new RegisterReplicationHubAccessCommand(Database.Name, hubTaskName, access, cert, GetRaftRequestIdFromQuery());
                var result  = await Server.ServerStore.SendToLeaderAsync(command);
                await WaitForIndexToBeApplied(context, result.Index);

                await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    writer.WriteStartObject();
                    writer.WritePropertyName(nameof(ReplicationHubAccessResponse.RaftCommandIndex));
                    writer.WriteInteger(result.Index);
                    writer.WriteEndObject();
                }
            }
        }
        public CreateDatabaseOperation(DatabaseRecord databaseRecord)
        {
            if (databaseRecord == null)
            {
                throw new ArgumentNullException(nameof(databaseRecord));
            }

            ResourceNameValidator.AssertValidDatabaseName(databaseRecord.DatabaseName);
            _databaseRecord    = databaseRecord;
            _replicationFactor = databaseRecord.Topology?.ReplicationFactor > 0 ? databaseRecord.Topology.ReplicationFactor : 1;
        }
        public UpdateDatabaseOperation(DatabaseRecord databaseRecord, long etag)
        {
            if (databaseRecord == null)
            {
                throw new ArgumentNullException(nameof(databaseRecord));
            }

            ResourceNameValidator.AssertValidDatabaseName(databaseRecord.DatabaseName);
            _databaseRecord    = databaseRecord;
            _etag              = etag;
            _replicationFactor = databaseRecord.Topology?.ReplicationFactor > 0 ? databaseRecord.Topology.ReplicationFactor : throw new ArgumentException($"{nameof(databaseRecord)}.{nameof(databaseRecord.Topology)}.{nameof(databaseRecord.Topology.ReplicationFactor)} is missing.");
        }
Example #10
0
        public void DatabaseNameWithDocsValidation()
        {
            Assert.False(ResourceNameValidator.IsValidResourceName(".", null, out _));
            Assert.False(ResourceNameValidator.IsValidResourceName("..", null, out _));
            Assert.False(ResourceNameValidator.IsValidResourceName("...", null, out _));
            Assert.False(ResourceNameValidator.IsValidResourceName("../..", null, out _));
            Assert.False(ResourceNameValidator.IsValidResourceName("../../aa", null, out _));
            Assert.False(ResourceNameValidator.IsValidResourceName("..\\..", null, out _));
            Assert.False(ResourceNameValidator.IsValidResourceName("..\\..\\aa", null, out _));

            Assert.True(ResourceNameValidator.IsValidResourceName("a.a", null, out _));
            Assert.True(ResourceNameValidator.IsValidResourceName("4.a", null, out _));
        }
        public CreateDatabaseOperation(DatabaseRecord databaseRecord, int replicationFactor)
        {
            if (databaseRecord == null)
            {
                throw new ArgumentNullException(nameof(databaseRecord));
            }

            if (replicationFactor <= 0)
            {
                throw new ArgumentException(nameof(replicationFactor));
            }

            ResourceNameValidator.AssertValidDatabaseName(databaseRecord.DatabaseName);
            _databaseRecord    = databaseRecord;
            _replicationFactor = replicationFactor;
        }
Example #12
0
        public async Task IsValidName()
        {
            if (Enum.TryParse(GetQueryStringValueAndAssertIfSingleAndNotEmpty("type").Trim(), out ItemType elementType) == false)
            {
                throw new ArgumentException($"Type {elementType} is not supported");
            }

            var name = GetQueryStringValueAndAssertIfSingleAndNotEmpty("name").Trim();
            var path = GetStringQueryString("dataPath", false);

            using (ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext context))
            {
                bool   isValid      = true;
                string errorMessage = null;

                switch (elementType)
                {
                case ItemType.Database:
                    isValid = ResourceNameValidator.IsValidResourceName(name, path, out errorMessage);
                    break;

                case ItemType.Index:
                    isValid = IndexStore.IsValidIndexName(name, isStatic: true, out errorMessage);
                    break;

                case ItemType.Script:
                    isValid = ResourceNameValidator.IsValidFileName(name, out errorMessage);
                    break;

                case ItemType.ElasticSearchIndex:
                    isValid = ElasticSearchIndexValidator.IsValidIndexName(name, out errorMessage);
                    break;
                }

                await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    context.Write(writer, new DynamicJsonValue
                    {
                        [nameof(NameValidation.IsValid)]      = isValid,
                        [nameof(NameValidation.ErrorMessage)] = errorMessage
                    });
                }
            }
        }
Example #13
0
        protected async Task DatabaseConfigurations(SetupFunc setupConfigurationFunc,
                                                    string debug,
                                                    string raftRequestId,
                                                    RefAction beforeSetupConfiguration = null,
                                                    Action <DynamicJsonValue, BlittableJsonReaderObject, long> fillJson = null,
                                                    HttpStatusCode statusCode = HttpStatusCode.OK)
        {
            if (TryGetAllowedDbs(Database.Name, out var _, requireAdmin: true) == false)
            {
                return;
            }

            if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false)
            {
                throw new BadRequestException(errorMessage);
            }

            await ServerStore.EnsureNotPassiveAsync();

            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
            {
                var configurationJson = await context.ReadForMemoryAsync(RequestBodyStream(), debug);

                beforeSetupConfiguration?.Invoke(Database.Name, ref configurationJson, context);

                var(index, _) = await setupConfigurationFunc(context, Database.Name, configurationJson, raftRequestId);
                await WaitForIndexToBeApplied(context, index);

                HttpContext.Response.StatusCode = (int)statusCode;

                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    var json = new DynamicJsonValue
                    {
                        ["RaftCommandIndex"] = index,
                    };
                    fillJson?.Invoke(json, configurationJson, index);
                    context.Write(writer, json);
                    writer.Flush();
                }
            }
        }
Example #14
0
        protected RestoreBackupTaskBase(ServerStore serverStore,
                                        RestoreBackupConfigurationBase restoreFromConfiguration,
                                        string nodeTag,
                                        OperationCancelToken operationCancelToken)
        {
            _serverStore             = serverStore;
            RestoreFromConfiguration = restoreFromConfiguration;
            _nodeTag = nodeTag;
            _operationCancelToken = operationCancelToken;

            var dataDirectoryThatWillBeUsed = string.IsNullOrWhiteSpace(RestoreFromConfiguration.DataDirectory) ?
                                              _serverStore.Configuration.Core.DataDirectory.FullPath :
                                              new PathSetting(RestoreFromConfiguration.DataDirectory, _serverStore.Configuration.Core.DataDirectory.FullPath).FullPath;

            if (ResourceNameValidator.IsValidResourceName(RestoreFromConfiguration.DatabaseName, dataDirectoryThatWillBeUsed, out string errorMessage) == false)
            {
                throw new InvalidOperationException(errorMessage);
            }

            _serverStore.EnsureNotPassive();

            ClusterTopology clusterTopology;

            using (_serverStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
                using (context.OpenReadTransaction())
                {
                    if (_serverStore.Cluster.DatabaseExists(context, RestoreFromConfiguration.DatabaseName))
                    {
                        throw new ArgumentException($"Cannot restore data to an existing database named {RestoreFromConfiguration.DatabaseName}");
                    }

                    clusterTopology = _serverStore.GetClusterTopology(context);
                }

            _hasEncryptionKey = string.IsNullOrWhiteSpace(RestoreFromConfiguration.EncryptionKey) == false;
            if (_hasEncryptionKey)
            {
                var key = Convert.FromBase64String(RestoreFromConfiguration.EncryptionKey);
                if (key.Length != 256 / 8)
                {
                    throw new InvalidOperationException($"The size of the key must be 256 bits, but was {key.Length * 8} bits.");
                }

                if (AdminDatabasesHandler.NotUsingHttps(clusterTopology.GetUrlFromTag(_serverStore.NodeTag)))
                {
                    throw new InvalidOperationException("Cannot restore an encrypted database to a node which doesn't support SSL!");
                }
            }

            var backupEncryptionSettings = RestoreFromConfiguration.BackupEncryptionSettings;

            if (backupEncryptionSettings != null)
            {
                if (backupEncryptionSettings.EncryptionMode == EncryptionMode.UseProvidedKey &&
                    backupEncryptionSettings.Key == null)
                {
                    throw new InvalidOperationException($"{nameof(BackupEncryptionSettings.EncryptionMode)} is set to {nameof(EncryptionMode.UseProvidedKey)} but an encryption key wasn't provided");
                }


                if (backupEncryptionSettings.EncryptionMode != EncryptionMode.UseProvidedKey &&
                    backupEncryptionSettings.Key != null)
                {
                    throw new InvalidOperationException($"{nameof(BackupEncryptionSettings.EncryptionMode)} is set to {backupEncryptionSettings.EncryptionMode} but an encryption key was provided");
                }
            }

            var hasRestoreDataDirectory = string.IsNullOrWhiteSpace(RestoreFromConfiguration.DataDirectory) == false;

            if (hasRestoreDataDirectory &&
                HasFilesOrDirectories(dataDirectoryThatWillBeUsed))
            {
                throw new ArgumentException("New data directory must be empty of any files or folders, " +
                                            $"path: {dataDirectoryThatWillBeUsed}");
            }

            if (hasRestoreDataDirectory == false)
            {
                RestoreFromConfiguration.DataDirectory = GetDataDirectory();
            }

            _restoringToDefaultDataDirectory = IsDefaultDataDirectory(RestoreFromConfiguration.DataDirectory, RestoreFromConfiguration.DatabaseName);
        }
 public PromoteDatabaseNodeOperation(string databaseName, string node)
 {
     ResourceNameValidator.AssertValidDatabaseName(databaseName);
     _databaseName = databaseName;
     _node         = node;
 }
 public UpdateDatabaseOperation(DatabaseRecord databaseRecord, long etag)
 {
     ResourceNameValidator.AssertValidDatabaseName(databaseRecord.DatabaseName);
     _databaseRecord = databaseRecord;
     _etag           = etag;
 }
 public ConfigureRevisionsForConflictsOperation(string database, RevisionsCollectionConfiguration configuration)
 {
     ResourceNameValidator.AssertValidDatabaseName(database);
     _database      = database;
     _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
 }
 public CreateDatabaseOperation(DatabaseRecord databaseRecord, int replicationFactor = 1)
 {
     ResourceNameValidator.AssertValidDatabaseName(databaseRecord.DatabaseName);
     _databaseRecord    = databaseRecord;
     _replicationFactor = replicationFactor;
 }