public async Task <IActionResult> GetVariables([FromRoute] string name, [FromRoute] int structureVersion, [FromQuery] int offset = -1, [FromQuery] int length = -1) { if (string.IsNullOrWhiteSpace(name)) { return(BadRequest("no name provided")); } if (structureVersion <= 0) { return(BadRequest($"invalid version provided '{structureVersion}'")); } var range = QueryRange.Make(offset, length); var identifier = new StructureIdentifier(name, structureVersion); try { var result = await _store.Structures.GetVariables(identifier, range); return(Result(result)); } catch (Exception e) { Logger.LogError(e, $"failed to retrieve structure-variables of ({nameof(name)}: {name}, {nameof(structureVersion)}: {structureVersion})"); return(StatusCode(HttpStatusCode.InternalServerError, "failed to retrieve structure")); } }
public async Task <IActionResult> GetVariablesJson([FromRoute] string name, [FromRoute] int structureVersion) { if (string.IsNullOrWhiteSpace(name)) { return(BadRequest("no name provided")); } if (structureVersion <= 0) { return(BadRequest($"invalid version provided '{structureVersion}'")); } var identifier = new StructureIdentifier(name, structureVersion); try { var result = await _store.Structures.GetVariables(identifier, QueryRange.All); if (result.IsError) { return(ProviderError(result)); } var json = _translator.ToJson(result.Data); return(Ok(json)); } catch (Exception e) { Logger.LogError(e, $"failed to retrieve structure-variables of ({nameof(name)}: {name}, {nameof(structureVersion)}: {structureVersion})"); return(StatusCode(HttpStatusCode.InternalServerError, "failed to retrieve structure")); } }
private async Task <(IDictionary <string, string> Structure, IDictionary <string, string> Variables)> ResolveStructurePreview(StructurePreview structure) { if (!string.IsNullOrWhiteSpace(structure.Name) && !string.IsNullOrWhiteSpace(structure.Version)) { int.TryParse(structure.Version, out var structureVersion); var id = new StructureIdentifier(structure.Name, structureVersion); var structResult = await _store.Structures.GetKeys(id, QueryRange.All); var variableResult = await _store.Structures.GetVariables(id, QueryRange.All); if (!structResult.IsError && !variableResult.IsError) { return(Structure : structResult.Data, Variables : variableResult.Data); } Logger.LogWarning($"could not retrieve referenced structure / variables '{id}' for preview: " + $"{(structResult.IsError ? structResult.Message : variableResult.Message)}"); } return(Structure : structure.Keys?.ToDictionary(pair => pair.Key, pair => pair.Value?.ToString()) ?? new Dictionary <string, string>(), Variables : structure.Variables?.ToDictionary(pair => pair.Key, pair => pair.Value?.ToString()) ?? new Dictionary <string, string>()); }
public void GetHashCodeStable(string name, int version) { var identifier = new StructureIdentifier(name, version); var hashes = Enumerable.Range(0, 1000) .Select(i => identifier.GetHashCode()) .ToList(); var example = identifier.GetHashCode(); Assert.True(hashes.All(h => h == example), "hashes.All(h=>h==example)"); }
public async Task <IActionResult> GetConfigurationJson([FromRoute] string environmentCategory, [FromRoute] string environmentName, [FromRoute] string structureName, [FromRoute] int structureVersion, [FromQuery] DateTime when) { try { var envIdentifier = new EnvironmentIdentifier(environmentCategory, environmentName); var structureIdentifier = new StructureIdentifier(structureName, structureVersion); var configId = new ConfigurationIdentifier(envIdentifier, structureIdentifier, default); var result = await _store.Configurations.GetJson(configId, when); if (result.IsError) { return(ProviderError(result)); } var json = result.Data; if (json.ValueKind == JsonValueKind.Null) { return(StatusCode(HttpStatusCode.InternalServerError, "failed to translate keys to json")); } var version = await _store.Configurations.GetVersion(configId, when); if (version.IsError) { return(ProviderError(version)); } // add version to the response-headers Response.Headers.Add("x-version", version.Data); return(Ok(json)); } catch (Exception e) { Logger.LogError(e, "failed to retrieve configuration for (" + $"{nameof(environmentCategory)}: {environmentCategory}, " + $"{nameof(environmentName)}: {environmentName}, " + $"{nameof(structureName)}: {structureName}, " + $"{nameof(structureVersion)}: {structureVersion}, " + $"{nameof(when)}: {when:O})"); return(StatusCode(HttpStatusCode.InternalServerError, "failed to retrieve configuration")); } }
public async Task <IActionResult> GetConfiguration([FromRoute] string environmentCategory, [FromRoute] string environmentName, [FromRoute] string structureName, [FromRoute] int structureVersion, [FromQuery] DateTime when, [FromQuery] int offset = -1, [FromQuery] int length = -1) { try { var range = QueryRange.Make(offset, length); var envIdentifier = new EnvironmentIdentifier(environmentCategory, environmentName); var structureIdentifier = new StructureIdentifier(structureName, structureVersion); var configId = new ConfigurationIdentifier(envIdentifier, structureIdentifier, default); var result = await _store.Configurations.GetKeys(configId, when, range); if (result.IsError) { return(ProviderError(result)); } var version = await _store.Configurations.GetVersion(configId, when); if (version.IsError) { return(ProviderError(version)); } // add version to the response-headers Response.Headers.Add("x-version", version.Data); return(Result(result)); } catch (Exception e) { KnownMetrics.Exception.WithLabels(e.GetType().Name).Inc(); Logger.LogError(e, "failed to add new environment at (" + $"{nameof(environmentCategory)}: {environmentCategory}; " + $"{nameof(environmentName)}: {environmentName}; " + $"{nameof(structureName)}: {structureName}; " + $"{nameof(structureVersion)}: {structureVersion}; " + $"{nameof(when)}: {when}; " + $"{nameof(offset)}: {offset}; " + $"{nameof(length)}: {length})"); return(StatusCode(HttpStatusCode.InternalServerError, "failed to retrieve configuration")); } }
public void InitializedProperties() { var identifier = new StructureIdentifier("FooBar", 42); var item = new ConfigStructure(identifier); Assert.NotNull(item.Keys); Assert.Empty(item.Keys); Assert.NotNull(item.Variables); Assert.Empty(item.Variables); Assert.False(item.Created); Assert.False(item.Deleted); // use this comparison because we don't care about reference-equality, only value-equality Assert.True(identifier.Equals(item.Identifier), "identifier.Equals(item.Identifier)"); }
/// <summary> /// validate a single <see cref="StructureIdentifier" /> /// </summary> /// <param name="identifier"></param> /// <returns></returns> private IResult ValidateIdentifier(StructureIdentifier identifier) { if (identifier is null) { return(Result.Error("invalid StructureIdentifier (null)", ErrorCode.ValidationFailed)); } if (string.IsNullOrWhiteSpace(identifier.Name)) { return(Result.Error("invalid StructureIdentifier.Name (empty / null)", ErrorCode.ValidationFailed)); } if (identifier.Version <= 0) { return(Result.Error("invalid StructureIdentifier.Version (x <= 0)", ErrorCode.ValidationFailed)); } return(Result.Success()); }
/// <inheritdoc /> public async Task <IResult <IDictionary <string, string> > > GetVariables(StructureIdentifier identifier, QueryRange range) { try { _logger.LogDebug($"retrieving variables of structure '{identifier}'"); var structResult = await _domainObjectStore.ReplayObject(new ConfigStructure(identifier), identifier.ToString()); if (structResult.IsError) { return(Result.Error <IDictionary <string, string> >("no structure found with (" + $"{nameof(identifier.Name)}: {identifier.Name}; " + $"{nameof(identifier.Version)}: {identifier.Version}" + ")", ErrorCode.NotFound)); } var structure = structResult.Data; _logger.LogDebug($"got structure at version '{structure.CurrentVersion}' / {structure.MetaVersion}"); var result = structure.Variables .OrderBy(v => v.Key) .Skip(range.Offset) .Take(range.Length) .ToImmutableSortedDictionary(k => k.Key, k => k.Value, StringComparer.OrdinalIgnoreCase); return(Result.Success <IDictionary <string, string> >(result)); } catch (Exception e) { _logger.LogError("failed to retrieve variables for structure " + $"({nameof(identifier.Name)}: {identifier.Name}; {nameof(identifier.Version)}: {identifier.Version}): {e}"); return(Result.Error <IDictionary <string, string> >( "failed to retrieve variables for structure " + $"({nameof(identifier.Name)}: {identifier.Name}; {nameof(identifier.Version)}: {identifier.Version})", ErrorCode.DbQueryError)); } }
public async Task <IActionResult> UpdateVariables([FromRoute] string name, [FromRoute] int structureVersion, [FromBody] Dictionary <string, string> changes) { if (string.IsNullOrWhiteSpace(name)) { return(BadRequest("no name received")); } if (structureVersion <= 0) { return(BadRequest("invalid version version received")); } if (changes is null || !changes.Any()) { return(BadRequest("no changes received")); } try { var identifier = new StructureIdentifier(name, structureVersion); var result = await _store.Structures.UpdateVariables(identifier, changes); if (result.IsError) { return(ProviderError(result)); } return(AcceptedAtAction(nameof(GetVariables), RouteUtilities.ControllerName <StructureController>(), new { version = ApiVersions.V1, name, structureVersion })); } catch (Exception e) { Logger.LogError(e, $"failed to update structure-variables for ({nameof(name)}: {name}, {nameof(structureVersion)}: {structureVersion})"); return(StatusCode(HttpStatusCode.InternalServerError, $"failed to update structure-variables for ({nameof(name)}: {name}, {nameof(structureVersion)}: {structureVersion})")); } }
public async Task <IActionResult> GetUsedKeys([FromRoute] string environmentCategory, [FromRoute] string environmentName, [FromRoute] string structureName, [FromRoute] int structureVersion, [FromQuery] DateTime when, [FromQuery] int offset = -1, [FromQuery] int length = -1) { try { var range = QueryRange.Make(offset, length); var envIdentifier = new EnvironmentIdentifier(environmentCategory, environmentName); var structureIdentifier = new StructureIdentifier(structureName, structureVersion); var result = await _store.Configurations.GetUsedConfigurationKeys( new ConfigurationIdentifier( envIdentifier, structureIdentifier, default), when, range); return(Result(result)); } catch (Exception e) { KnownMetrics.Exception.WithLabels(e.GetType().Name).Inc(); Logger.LogError(e, "failed to add new environment at (" + $"{nameof(environmentCategory)}: {environmentCategory}; " + $"{nameof(environmentName)}: {environmentName}; " + $"{nameof(structureName)}: {structureName}; " + $"{nameof(structureVersion)}: {structureVersion}; " + $"{nameof(when)}: {when}; " + $"{nameof(offset)}: {offset}; " + $"{nameof(length)}: {length})"); return(StatusCode(HttpStatusCode.InternalServerError, "failed to retrieve used keys in configuration")); } }
/// <inheritdoc /> public async Task <IResult> Create(StructureIdentifier identifier, IDictionary <string, string> keys, IDictionary <string, string> variables) { _logger.LogDebug($"attempting to create new structure '{identifier}'"); var structResult = await _domainObjectStore.ReplayObject(new ConfigStructure(identifier), identifier.ToString()); if (structResult.IsError) { return(structResult); } var structure = structResult.Data; _logger.LogDebug("creating Structure"); var result = structure.Create(keys, variables); if (result.IsError) { return(result); } _logger.LogDebug("validating resulting events"); var errors = structure.Validate(_validators); if (errors.Any()) { return(Result.Error("failed to validate generated DomainEvents", ErrorCode.ValidationFailed, errors.Values .SelectMany(_ => _) .ToList())); } _logger.LogDebug("writing generated events to ES"); return(await structure.WriteRecordedEvents(_eventStore)); }
/// <inheritdoc /> public ConfigStructure(StructureIdentifier identifier) { if (identifier is null) { throw new ArgumentNullException(nameof(identifier)); } if (string.IsNullOrWhiteSpace(identifier.Name)) { throw new ArgumentNullException(nameof(identifier), $"{nameof(identifier.Name)} is null or empty"); } if (identifier.Version <= 0) { throw new ArgumentNullException(nameof(identifier), $"{nameof(identifier.Version)} is null or empty"); } Created = false; Deleted = false; Identifier = new StructureIdentifier(identifier.Name, identifier.Version); Keys = new Dictionary <string, string>(); Variables = new Dictionary <string, string>(); }
/// <inheritdoc /> public async Task <IResult> DeleteVariables(StructureIdentifier identifier, ICollection <string> variablesToDelete) { _logger.LogDebug($"attempting to delete variables from structure '{identifier}'"); var structResult = await _domainObjectStore.ReplayObject(new ConfigStructure(identifier), identifier.ToString()); if (structResult.IsError) { return(structResult); } var structure = structResult.Data; _logger.LogDebug($"removing '{variablesToDelete.Count}' variables from '{identifier}' " + $"at version '{structure.CurrentVersion}' / {structure.MetaVersion}"); var updateResult = structure.DeleteVariables(variablesToDelete); if (updateResult.IsError) { return(updateResult); } _logger.LogDebug("validating resulting events"); var errors = structure.Validate(_validators); if (errors.Any()) { return(Result.Error("failed to validate generated DomainEvents", ErrorCode.ValidationFailed, errors.Values .SelectMany(_ => _) .ToList())); } return(await structure.WriteRecordedEvents(_eventStore)); }
/// <inheritdoc /> public async Task <IResult <IList <ConfigurationIdentifier> > > GetAvailableWithStructure(StructureIdentifier structure, DateTime when, QueryRange range) { try { _logger.LogDebug($"collecting available configurations at '{when:O}', range={range}"); var list = await _domainObjectStore.ReplayObject <PreparedConfigurationList>(); if (list.IsError) { return(Result.Success <IList <ConfigurationIdentifier> >(new List <ConfigurationIdentifier>())); } var utcWhen = when.ToUniversalTime(); _logger.LogDebug($"using utc-time={utcWhen:O}"); var identifiers = list.Data .GetIdentifiers() .Where(pair => (pair.Value.ValidFrom ?? DateTime.MinValue) <= utcWhen && (pair.Value.ValidTo ?? DateTime.MaxValue) >= utcWhen) .Where(pair => pair.Key.Structure.Name == structure.Name && pair.Key.Structure.Version == structure.Version) .OrderBy(pair => pair.Key.Environment.Category) .ThenBy(pair => pair.Key.Environment.Name) .ThenBy(pair => pair.Key.Structure.Name) .ThenByDescending(s => s.Key.Structure.Version) .Skip(range.Offset) .Take(range.Length) .Select(pair => pair.Key) .ToList(); _logger.LogDebug($"collected '{identifiers.Count}' identifiers"); return(Result.Success <IList <ConfigurationIdentifier> >(identifiers)); } catch (Exception e) { _logger.LogError(e, "failed to retrieve projected configurations"); return(Result.Error <IList <ConfigurationIdentifier> >("failed to retrieve projected configurations", ErrorCode.DbQueryError)); } }
public async Task <IActionResult> PreviewConfiguration([FromRoute] string environmentCategory, [FromRoute] string environmentName, [FromRoute] string structureName, [FromRoute] int structureVersion) { var envId = new EnvironmentIdentifier(environmentCategory, environmentName); var structId = new StructureIdentifier(structureName, structureVersion); var structureKeyResult = await _store.Structures.GetKeys(structId, QueryRange.All); if (structureKeyResult.IsError) { return(ProviderError(structureKeyResult)); } var structureVariableResult = await _store.Structures.GetVariables(structId, QueryRange.All); if (structureVariableResult.IsError) { return(ProviderError(structureVariableResult)); } var environmentResult = await _store.Environments.GetKeys(new EnvironmentKeyQueryParameters { Environment = envId, Range = QueryRange.All }); if (environmentResult.IsError) { return(ProviderError(environmentResult)); } var structureSnapshot = structureKeyResult.Data; var variableSnapshot = structureVariableResult.Data; var environmentSnapshot = environmentResult.Data; var environmentInfo = new EnvironmentCompilationInfo { Name = $"{envId.Category}/{envId.Name}", Keys = environmentSnapshot }; var structureInfo = new StructureCompilationInfo { Name = $"{structId.Name}/{structId.Version}", Keys = structureSnapshot, Variables = variableSnapshot }; try { var compiled = _compiler.Compile(environmentInfo, structureInfo, _parser); var json = _translator.ToJson(compiled.CompiledConfiguration); return(Ok(json)); } catch (Exception e) { KnownMetrics.Exception.WithLabels(e.GetType().Name).Inc(); Logger.LogError(e, "failed to add new environment at (" + $"{nameof(environmentCategory)}: {environmentCategory}; " + $"{nameof(environmentName)}: {environmentName}; " + $"{nameof(structureName)}: {structureName}; " + $"{nameof(structureVersion)}: {structureVersion})"); return(Ok(JsonDocument.Parse("{}").RootElement)); } }
public async Task <IActionResult> InspectStructure([FromRoute] string environmentCategory, [FromRoute] string environmentName, [FromRoute] string structureName, [FromRoute] int structureVersion) { if (string.IsNullOrWhiteSpace(environmentCategory)) { return(BadRequest("no environment-category given")); } if (string.IsNullOrWhiteSpace(environmentName)) { return(BadRequest("no environment-name given")); } if (string.IsNullOrWhiteSpace(structureName)) { return(BadRequest("no structure-name was given")); } if (structureVersion <= 0) { return(BadRequest("structure-version invalid")); } var envId = new EnvironmentIdentifier(environmentCategory, environmentName); var structId = new StructureIdentifier(structureName, structureVersion); var envKeysResult = await _store.Environments.GetKeys(new EnvironmentKeyQueryParameters { Environment = envId, Range = QueryRange.All }); if (envKeysResult.IsError) { return(ProviderError(envKeysResult)); } var envKeys = envKeysResult.Data; IDictionary <string, string> structKeys; IDictionary <string, string> structVars; try { var keyResult = await _store.Structures.GetKeys(structId, QueryRange.All); if (keyResult.IsError) { return(ProviderError(keyResult)); } var varResult = await _store.Structures.GetVariables(structId, QueryRange.All); if (varResult.IsError) { return(ProviderError(varResult)); } structKeys = keyResult.Data; structVars = varResult.Data; } catch (Exception e) { Logger.LogWarning(e, "could not retrieve structure-data or -variables"); return(BadRequest("could not retrieve structure-data or -variables")); } CompilationResult compilationResult; try { compilationResult = _compiler.Compile( new EnvironmentCompilationInfo { Keys = envKeys, Name = envId.ToString() }, new StructureCompilationInfo { Name = structureName, Keys = structKeys, Variables = structVars }, _parser); } catch (Exception e) { Logger.LogWarning(e, $"structure could not be inspected in context of '{envId}'; compilation failed"); return(Ok(new StructureInspectionResult { CompilationSuccessful = false })); } var result = AnalyzeCompilation(compilationResult); return(Ok(result)); }