private async Task CheckConnectivity(ClusterDatabaseHost resource) { _logger.LogDebug( @"Cluster database host ""{name}"" connection check.", resource.Metadata.Name); resource.Status.LastConnectionTest = DateTime.UtcNow; await using var host = _connectionsManager.GetHost(resource.Metadata.Name); try { await host.CanConnect(); resource.Status.Connected = true; resource.Status.Error = null; } catch (Exception e) { resource.Status.Connected = false; resource.Status.Error = e.Message; } finally { try { await Client.UpdateStatus(resource); } catch (Exception e) { _logger.LogError( e, @"Could not update status on resource ""{kind}/{name}"".", resource.Kind, resource.Metadata.Name); } } }
public override async Task Finalize(HostedDatabase resource) { // TODO create a soft-delete for database await using var host = _connectionsManager.GetHost(resource.Spec.Host); _logger.LogDebug( @"Delete and cleanup database ""{database}"".", resource.Metadata.Name); var @namespace = resource.Metadata.NamespaceProperty; var configMapName = $"{resource.Metadata.Name}-config"; var configMap = await Client.Get <V1ConfigMap>(configMapName, @namespace); var db = configMap?.Data["database"] ?? host.FormatDatabaseName(resource.Metadata.Name); var configs = await Client.List <V1ConfigMap>( @namespace, new EqualsSelector("managed-by", "hosted-database-operator"), new EqualsSelector("database-instance", db)); var secrets = await Client.List <V1Secret>( @namespace, new EqualsSelector("managed-by", "hosted-database-operator"), new EqualsSelector("database-instance", db)); await host.Teardown(db); await Client.Delete(configs); await Client.Delete(secrets); _logger.LogInformation( @"Finalize for database ""{database}"" executed. Removed database, user, config and secrets.", resource.Metadata.Name); }
private async Task CheckDatabase(HostedDatabase resource) { try { await using var host = _connectionsManager.GetHost(resource.Spec.Host); var @namespace = resource.Metadata.NamespaceProperty; var secretName = $"{resource.Metadata.Name}-auth"; var configMapName = $"{resource.Metadata.Name}-config"; var configMap = await Client.Get <V1ConfigMap>(configMapName, @namespace); if (configMap == null) { configMap = new V1ConfigMap( V1ConfigMap.KubeApiVersion, kind: V1ConfigMap.KubeKind, metadata: new V1ObjectMeta { Name = configMapName, NamespaceProperty = @namespace, OwnerReferences = new List <V1OwnerReference> { new V1OwnerReference(resource.ApiVersion, resource.Kind, resource.Metadata.Name, resource.Metadata.Uid, false, true), } }); configMap.Data = new Dictionary <string, string> { ["host"] = host.Config.Host, ["port"] = host.Config.Port.ToString(), ["database"] = host.FormatDatabaseName(resource.Metadata.Name), }; configMap.Metadata.Labels = new Dictionary <string, string> { ["managed-by"] = "hosted-database-operator", ["database-instance"] = host.FormatDatabaseName(resource.Metadata.Name), }; configMap = await Client.Create(configMap); _logger.LogDebug( @"Create config map ""{configName}"" for database ""{database}"".", configMap.Metadata.Name, resource.Metadata.Name); } var secret = await Client.Get <V1Secret>(secretName, @namespace); if (secret == null) { _logger.LogDebug( @"Secret ""{name}"" did not exist. Create Secret and User.", secretName); secret = new V1Secret( V1Secret.KubeApiVersion, kind: V1Secret.KubeKind, metadata: new V1ObjectMeta { Name = secretName, NamespaceProperty = @namespace, OwnerReferences = new List <V1OwnerReference> { new V1OwnerReference(resource.ApiVersion, resource.Kind, resource.Metadata.Name, resource.Metadata.Uid, false, true), } }); secret.Data = new Dictionary <string, byte[]> { ["username"] = Encoding.UTF8.GetBytes(host.FormatUsername(resource.Metadata.Name)), }; secret.Metadata.Labels = new Dictionary <string, string> { ["managed-by"] = "hosted-database-operator", ["database-instance"] = host.FormatDatabaseName(resource.Metadata.Name), }; secret = await Client.Create(secret); } var db = configMap.Data["database"]; resource.Status.DbHost = $"{host.Config.Host}:{host.Config.Port}"; resource.Status.DbName ??= db; resource.Status.SecretName ??= secretName; resource.Status.ConfigMapName ??= configMapName; var user = secret.ReadData("username"); var password = await host.ProcessDatabase(db, user); if (password != null) { _logger.LogInformation( @"User ""{user}"" for database ""{database}"" updated password.", user, resource.Metadata.Name); secret.WriteData("password", password); await Client.Update(secret); } resource.Status.Error = null; } catch (Exception e) { resource.Status.Error = e.Message; _logger.LogError( e, @"Could not create / update / check database ""{database}"".", resource.Metadata.Name); throw; } finally { await Client.UpdateStatus(resource); } }