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"));
            }
        }
Beispiel #3
0
        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)");
        }
Beispiel #5
0
        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"));
            }
        }
Beispiel #6
0
        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"));
            }
        }
Beispiel #7
0
        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)");
        }
Beispiel #8
0
        /// <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})"));
            }
        }
Beispiel #11
0
        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));
            }
        }
Beispiel #16
0
        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));
            }
        }
Beispiel #17
0
        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));
        }