// Copyright 2016-2019, Pulumi Corporation using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Text.Json; namespace Pulumi { public partial class Deployment { /// /// The environment variable key that the language plugin uses to set configuration values. /// private const string _configEnvKey = "PULUMI_CONFIG"; /// /// The environment variable key that the language plugin uses to set the list of secret configuration keys. /// private const string _configSecretKeysEnvKey = "PULUMI_CONFIG_SECRET_KEYS"; /// /// Returns a copy of the full config map. /// internal ImmutableDictionary AllConfig { get; private set; } = ParseConfig(); /// /// Returns a copy of the config secret keys. /// internal ImmutableHashSet ConfigSecretKeys { get; private set; } = ParseConfigSecretKeys(); /// /// Sets a configuration variable. /// internal void SetConfig(string key, string value) => AllConfig = AllConfig.Add(key, value); /// /// Appends all provided configuration. /// internal void SetAllConfig(IDictionary config, IEnumerable? secretKeys = null) { AllConfig = AllConfig.AddRange(config); if (secretKeys != null) { ConfigSecretKeys = ConfigSecretKeys.Union(secretKeys); } } /// /// Returns a configuration variable's value or if it is unset. /// string? IDeploymentInternal.GetConfig(string key) => AllConfig.TryGetValue(key, out var value) ? value : null; /// /// Returns true if the key contains a secret value. /// bool IDeploymentInternal.IsConfigSecret(string fullKey) => ConfigSecretKeys.Contains(fullKey); private static ImmutableDictionary ParseConfig() { var parsedConfig = ImmutableDictionary.CreateBuilder(); var envConfig = Environment.GetEnvironmentVariable(_configEnvKey); if (envConfig != null) { var envObject = JsonDocument.Parse(envConfig); foreach (var prop in envObject.RootElement.EnumerateObject()) { parsedConfig[CleanKey(prop.Name)] = prop.Value.ToString(); } } return parsedConfig.ToImmutable(); } private static ImmutableHashSet ParseConfigSecretKeys() { var parsedConfigSecretKeys = ImmutableHashSet.CreateBuilder(); var envConfigSecretKeys = Environment.GetEnvironmentVariable(_configSecretKeysEnvKey); if (envConfigSecretKeys != null) { var envObject = JsonDocument.Parse(envConfigSecretKeys); foreach (var element in envObject.RootElement.EnumerateArray()) { parsedConfigSecretKeys.Add(element.GetString()); } } return parsedConfigSecretKeys.ToImmutable(); } /// /// CleanKey takes a configuration key, and if it is of the form "(string):config:(string)" /// removes the ":config:" portion. Previously, our keys always had the string ":config:" in /// them, and we'd like to remove it. However, the language host needs to continue to set it /// so we can be compatible with older versions of our packages. Once we stop supporting /// older packages, we can change the language host to not add this :config: thing and /// remove this function. /// private static string CleanKey(string key) { var idx = key.IndexOf(":", StringComparison.Ordinal); if (idx > 0 && key.Substring(idx + 1).StartsWith("config:", StringComparison.Ordinal)) { return key.Substring(0, idx) + ":" + key.Substring(idx + 1 + "config:".Length); } return key; } } }