// Copyright 2016-2019, Pulumi Corporation using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text.Json; namespace Pulumi { /// /// is a bag of related configuration state. Each bag contains any number /// of configuration variables, indexed by simple keys, and each has a name that uniquely /// identifies it; two bags with different names do not share values for variables that /// otherwise share the same key. For example, a bag whose name is pulumi:foo, with keys /// a, b, and c, is entirely separate from a bag whose name is /// pulumi:bar with the same simple key names. Each key has a fully qualified names, /// such as pulumi:foo:a, ..., and pulumi:bar:a, respectively. /// public sealed partial class Config { /// /// is the configuration bag's logical name and uniquely identifies it. /// The default is the name of the current project. /// private readonly string _name; /// /// Creates a new instance. is the /// configuration bag's logical name and uniquely identifies it. The default is the name of /// the current project. /// public Config(string? name = null) { name ??= Deployment.Instance.ProjectName; if (name.EndsWith(":config", StringComparison.Ordinal)) { name = name[..^":config".Length]; } _name = name; } [return: NotNullIfNotNull("value")] private static Output? MakeClassSecret(T? value) where T : class => value == null ? null : Output.CreateSecret(value); private static Output? MakeStructSecret(T? value) where T : struct => value == null ? null : MakeStructSecret(value.Value); private static Output MakeStructSecret(T value) where T : struct => Output.CreateSecret(value); private string? GetImpl(string key, string? use = null, [CallerMemberName] string? insteadOf = null) { var fullKey = FullKey(key); // TODO[pulumi/pulumi#7127]: Re-enable the warning. // if (use != null && Deployment.InternalInstance.IsConfigSecret(fullKey)) // { // Debug.Assert(insteadOf != null); // Log.Warn($"Configuration '{fullKey}' value is a secret; use `{use}` instead of `{insteadOf}`"); // } return Deployment.InternalInstance.GetConfig(fullKey); } /// /// Loads an optional configuration value by its key, or if it doesn't exist. /// public string? Get(string key) => GetImpl(key, nameof(GetSecret)); /// /// Loads an optional configuration value by its key, marking it as a secret, or if it doesn't exist. /// public Output? GetSecret(string key) => MakeClassSecret(GetImpl(key)); private bool? GetBooleanImpl(string key, string? use = null, [CallerMemberName] string? insteadOf = null) { var v = GetImpl(key, use, insteadOf); return v switch { null => default(bool?), "true" => true, "false" => false, _ => throw new ConfigTypeException(FullKey(key), v, nameof(Boolean)) }; } /// /// Loads an optional configuration value, as a boolean, by its key, or null if it doesn't exist. /// If the configuration value isn't a legal boolean, this function will throw an error. /// public bool? GetBoolean(string key) => GetBooleanImpl(key, nameof(GetSecretBoolean)); /// /// Loads an optional configuration value, as a boolean, by its key, making it as a secret or /// null if it doesn't exist. If the configuration value isn't a legal boolean, this /// function will throw an error. /// public Output? GetSecretBoolean(string key) => MakeStructSecret(GetBooleanImpl(key)); private int? GetInt32Impl(string key, string? use = null, [CallerMemberName] string? insteadOf = null) { var v = GetImpl(key, use, insteadOf); return v == null ? default(int?) : int.TryParse(v, out var result) ? result : throw new ConfigTypeException(FullKey(key), v, nameof(Int32)); } /// /// Loads an optional configuration value, as a number, by its key, or null if it doesn't exist. /// If the configuration value isn't a legal number, this function will throw an error. /// public int? GetInt32(string key) => GetInt32Impl(key, nameof(GetSecretInt32)); /// /// Loads an optional configuration value, as a number, by its key, marking it as a secret /// or null if it doesn't exist. /// If the configuration value isn't a legal number, this function will throw an error. /// public Output? GetSecretInt32(string key) => MakeStructSecret(GetInt32Impl(key)); [return: MaybeNull] private T GetObjectImpl(string key, string? use = null, [CallerMemberName] string? insteadOf = null) { var v = GetImpl(key, use, insteadOf); try { return v == null ? default : JsonSerializer.Deserialize(v); } catch (JsonException ex) { throw new ConfigTypeException(FullKey(key), v, typeof(T).FullName!, ex); } } /// /// Loads an optional configuration value, as an object, by its key, or null if it doesn't /// exist. This works by taking the value associated with and passing /// it to . /// [return: MaybeNull] public T GetObject(string key) => GetObjectImpl(key, nameof(GetSecretObject)); /// /// Loads an optional configuration value, as an object, by its key, marking it as a secret /// or null if it doesn't exist. This works by taking the value associated with and passing it to . /// public Output? GetSecretObject(string key) { var v = GetImpl(key); if (v == null) return null; return Output.CreateSecret(GetObjectImpl(key)!); } private string RequireImpl(string key, string? use = null, [CallerMemberName] string? insteadOf = null) => GetImpl(key, use, insteadOf) ?? throw new ConfigMissingException(FullKey(key)); /// /// Loads a configuration value by its given key. If it doesn't exist, an error is thrown. /// public string Require(string key) => RequireImpl(key, nameof(RequireSecret)); /// /// Loads a configuration value by its given key, marking it as a secret. If it doesn't exist, an error /// is thrown. /// public Output RequireSecret(string key) => MakeClassSecret(RequireImpl(key)); private bool RequireBooleanImpl(string key, string? use = null, [CallerMemberName] string? insteadOf = null) => GetBooleanImpl(key, use, insteadOf) ?? throw new ConfigMissingException(FullKey(key)); /// /// Loads a configuration value, as a boolean, by its given key. If it doesn't exist, or the /// configuration value is not a legal boolean, an error is thrown. /// public bool RequireBoolean(string key) => RequireBooleanImpl(key, nameof(RequireSecretBoolean)); /// /// Loads a configuration value, as a boolean, by its given key, marking it as a secret. /// If it doesn't exist, or the configuration value is not a legal boolean, an error is thrown. /// public Output RequireSecretBoolean(string key) => MakeStructSecret(RequireBooleanImpl(key)); private int RequireInt32Impl(string key, string? use = null, [CallerMemberName] string? insteadOf = null) => GetInt32Impl(key, use, insteadOf) ?? throw new ConfigMissingException(FullKey(key)); /// /// Loads a configuration value, as a number, by its given key. If it doesn't exist, or the /// configuration value is not a legal number, an error is thrown. /// public int RequireInt32(string key) => RequireInt32Impl(key, nameof(RequireSecretInt32)); /// /// Loads a configuration value, as a number, by its given key, marking it as a secret. /// If it doesn't exist, or the configuration value is not a legal number, an error is thrown. /// public Output RequireSecretInt32(string key) => MakeStructSecret(RequireInt32Impl(key)); private T RequireObjectImpl(string key, string? use = null, [CallerMemberName] string? insteadOf = null) { var v = GetImpl(key); if (v == null) throw new ConfigMissingException(FullKey(key)); return GetObjectImpl(key, use, insteadOf)!; } /// /// Loads a configuration value as a JSON string and deserializes the JSON into an object. /// object. If it doesn't exist, or the configuration value cannot be converted using , an error is /// thrown. /// public T RequireObject(string key) => RequireObjectImpl(key, nameof(RequireSecretObject)); /// /// Loads a configuration value as a JSON string and deserializes the JSON into a JavaScript /// object, marking it as a secret. If it doesn't exist, or the configuration value cannot /// be converted using , /// an error is thrown. /// public Output RequireSecretObject(string key) => Output.CreateSecret(RequireObjectImpl(key)); /// /// Turns a simple configuration key into a fully resolved one, by prepending the bag's name. /// private string FullKey(string key) => $"{_name}:{key}"; } }