public static Secret CreateRegistrySecret( Output <string> @namespace, AutoDevOpsSettings.RegistrySettings registrySettings, ProviderResource?providerResource = null ) { const string secretName = "gitlab-registry"; var creds = $"{registrySettings.User}:{registrySettings.Password}".Base64Encode(); var content = $"{{\"auths\":{{\"{registrySettings.Server}\":{{\"email\":\"{registrySettings.Email}\", \"auth\":\"{creds}\"}}}}}}" .Base64Encode(); return(new Secret( secretName, new SecretArgs { Metadata = CreateArgs.GetMeta(secretName, @namespace), Type = "kubernetes.io/dockerconfigjson", Data = new InputMap <string> { { ".dockerconfigjson", content } } }, new CustomResourceOptions { Provider = providerResource } )); }
public static PodMonitor CreatePodMonitor( AutoDevOpsSettings settings, Pulumi.Kubernetes.Apps.V1.Deployment deployment, Namespace kubeNamespace, ProviderResource?providerResource = null ) => new(
public static Ingress Create( Output <string> namespaceName, AutoDevOpsSettings settings, string ingressClass, Dictionary <string, string>?annotations = null, ProviderResource?providerResource = null ) { var ingressLabels = settings.BaseLabels(); var tlsEnabled = settings.Ingress.Tls?.Enabled == true; var ingressAnnotations = (annotations ?? new Dictionary <string, string>()) .AsInputMap() .AddPair("kubernetes.io/ingress.class", ingressClass) .AddPairIf(tlsEnabled, "kubernetes.io/tls-acme", "true") .AddPairIf( settings.Prometheus.Metrics && ingressClass.Contains("nginx"), "nginx.ingress.kubernetes.io/server-snippet", "location /metrics { deny all; }" ); var uri = new Uri(settings.Deploy.Url); var ingress = new IngressArgs { Metadata = CreateArgs.GetMeta(settings.FullName(), namespaceName, ingressAnnotations, ingressLabels), Spec = new IngressSpecArgs { Rules = CreateArgs.IngressRule(uri.Host, settings.FullName(), settings.Service.ExternalPort), Tls = tlsEnabled ? new[] {
internal static async Task <string?> RegisterAsync(ProviderResource?provider) { if (provider == null) { return(null); } if (provider._registrationId == null) { var providerUrn = await provider.Urn.GetValueAsync(whenUnknown : default !).ConfigureAwait(false);
public static Deployment Create( Output <string> namespaceName, AutoDevOpsSettings settings, int replicas, Secret?imagePullSecret = null, Secret?appSecret = null, IEnumerable <ContainerArgs>?sidecars = null, Action <ContainerArgs>?configureContainer = null, Action <PodSpecArgs>?configurePod = null, Action <DeploymentArgs>?configureDeployment = null, ProviderResource?providerResource = null ) { var appLabels = settings.AppLabels(); var gitLabAnnotations = settings.GitLabAnnotations(); var containers = CreateArgs.GetAppContainers( settings.Application, settings.Deploy, settings.GitLab, appSecret, sidecars, configureContainer ); var deployment = new DeploymentArgs { Metadata = CreateArgs.GetMeta(settings.FullName(), namespaceName, gitLabAnnotations, appLabels), Spec = new DeploymentSpecArgs { Selector = new LabelSelectorArgs { MatchLabels = appLabels }, Replicas = replicas, Template = CreateArgs.GetPodTemplate( namespaceName, containers, imagePullSecret, appLabels, gitLabAnnotations, 60, configurePod ) } }; configureDeployment?.Invoke(deployment); return(new Deployment( settings.PulumiName("deployment"), deployment, new CustomResourceOptions { Provider = providerResource } )); }
public static Service Create( Output <string> namespaceName, AutoDevOpsSettings settings, Pulumi.Kubernetes.Apps.V1.Deployment deployment, Dictionary <string, string>?annotations = null, Action <ServiceArgs>?configureService = null, ProviderResource?providerResource = null ) { var selector = deployment.Spec.Apply(x => x.Selector.MatchLabels); return(Create(namespaceName, settings, selector, annotations, configureService, providerResource)); }
/// <summary> /// Create the application secret from CI variables, which are prefixed with K8S_SECRET_ /// </summary> /// <param name="namespaceName">Namespace, where the secret should be created</param> /// <param name="settings">AutoDevOps settings</param> /// <param name="providerResource">Optional: customer Kubernetes provider</param> /// <returns></returns> public static Secret?CreateAppSecret( Output <string> namespaceName, AutoDevOpsSettings settings, ProviderResource?providerResource = null ) { var env = GetEnvironmentVariables(); var vars = new Dictionary <string, string>(); foreach (DictionaryEntry entry in env) { var key = (string)entry.Key; if (key.StartsWith("K8S_SECRET_") && entry.Value != null) { vars[key.Remove(0, 11)] = (string)entry.Value; } } if (settings.Env != null) { foreach (var(name, value) in settings.Env) { vars[name] = value; } } if (vars.Count == 0) { return(null); } var secretName = $"{settings.Application.Name}-secret"; return(new Secret( secretName, new SecretArgs { Metadata = CreateArgs.GetMeta(secretName, namespaceName), Type = "opaque", StringData = vars }, new CustomResourceOptions { Provider = providerResource } )); }
internal static async Task <string?> RegisterAsync(ProviderResource?provider) { if (provider == null) { return(null); } if (provider._registrationId == null) { var providerURN = await provider.Urn.GetValueAsync().ConfigureAwait(false); var providerID = await provider.Id.GetValueAsync().ConfigureAwait(false); if (string.IsNullOrEmpty(providerID)) { providerID = Constants.UnknownValue; } provider._registrationId = $"{providerURN}::{providerID}"; } return(provider._registrationId); }
static Service Create( Output <string> namespaceName, AutoDevOpsSettings settings, InputMap <string> selector, Dictionary <string, string>?annotations = null, Action <ServiceArgs>?configureService = null, ProviderResource?providerResource = null ) { var serviceLabels = settings.BaseLabels(); var serviceAnnotations = (annotations ?? new Dictionary <string, string>()) .AsInputMap(); if (settings.Prometheus.Metrics && !settings.Prometheus.Operator) { serviceAnnotations .AddPair("prometheus.io/scrape", "true") .AddPair("prometheus.io/path", settings.Prometheus.Path) .AddPair("prometheus.io/port", settings.Service.ExternalPort.ToString()); } var serviceArgs = new ServiceArgs { Metadata = CreateArgs.GetMeta(settings.FullName(), namespaceName, serviceAnnotations, serviceLabels), Spec = new ServiceSpecArgs { Type = settings.Service.Type, Ports = new List <ServicePortArgs> { new() { Name = "web", Port = settings.Service.ExternalPort, TargetPort = settings.Application.Port, Protocol = "TCP" } },
/// <summary> /// Creates and registers a new resource object. <paramref name="type"/> is the fully /// qualified type token and <paramref name="name"/> is the "name" part to use in creating a /// stable and globally unique URN for the object. dependsOn is an optional list of other /// resources that this resource depends on, controlling the order in which we perform /// resource operations. /// </summary> /// <param name="type">The type of the resource.</param> /// <param name="name">The unique name of the resource.</param> /// <param name="custom">True to indicate that this is a custom resource, managed by a plugin.</param> /// <param name="args">The arguments to use to populate the new resource.</param> /// <param name="options">A bag of options that control this resource's behavior.</param> /// <param name="remote">True if this is a remote component resource.</param> /// <param name="dependency">True if this is a synthetic resource used internally for dependency tracking.</param> private protected Resource( string type, string name, bool custom, ResourceArgs args, ResourceOptions options, bool remote = false, bool dependency = false) { if (dependency) { _type = ""; _name = ""; _protect = false; _providers = ImmutableDictionary <string, ProviderResource> .Empty; return; } if (string.IsNullOrEmpty(type)) { throw new ArgumentException("'type' cannot be null or empty.", nameof(type)); } if (string.IsNullOrEmpty(name)) { throw new ArgumentException("'name' cannot be null or empty.", nameof(name)); } // Before anything else - if there are transformations registered, invoke them in order // to transform the properties and options assigned to this resource. var parent = type == Stack._rootPulumiStackTypeName ? null : (options.Parent ?? Deployment.InternalInstance.Stack); _type = type; _name = name; var transformations = ImmutableArray.CreateBuilder <ResourceTransformation>(); transformations.AddRange(options.ResourceTransformations); if (parent != null) { transformations.AddRange(parent._transformations); } this._transformations = transformations.ToImmutable(); foreach (var transformation in this._transformations) { var tres = transformation(new ResourceTransformationArgs(this, args, options)); if (tres != null) { if (tres.Value.Options.Parent != options.Parent) { // This is currently not allowed because the parent tree is needed to // establish what transformation to apply in the first place, and to compute // inheritance of other resource options in the Resource constructor before // transformations are run (so modifying it here would only even partially // take affect). It's theoretically possible this restriction could be // lifted in the future, but for now just disallow re-parenting resources in // transformations to be safe. throw new ArgumentException("Transformations cannot currently be used to change the 'parent' of a resource."); } args = tres.Value.Args; options = tres.Value.Options; } } // Make a shallow clone of options to ensure we don't modify the value passed in. options = options.Clone(); var componentOpts = options as ComponentResourceOptions; var customOpts = options as CustomResourceOptions; if (options.Provider != null && componentOpts?.Providers.Count > 0) { throw new ResourceException("Do not supply both 'provider' and 'providers' options to a ComponentResource.", options.Parent); } // Check the parent type if one exists and fill in any default options. this._providers = ImmutableDictionary <string, ProviderResource> .Empty; if (options.Parent != null) { var parentResource = options.Parent; lock (parentResource.ChildResources) { parentResource.ChildResources.Add(this); } options.Protect ??= options.Parent._protect; // Make a copy of the aliases array, and add to it any implicit aliases inherited from its parent options.Aliases = options.Aliases.ToList(); foreach (var parentAlias in options.Parent._aliases) { options.Aliases.Add(Pulumi.Urn.InheritedChildAlias(name, options.Parent.GetResourceName(), parentAlias, type)); } this._providers = options.Parent._providers; } if (custom) { var provider = customOpts?.Provider; if (provider == null) { if (options.Parent != null) { // If no provider was given, but we have a parent, then inherit the // provider from our parent. options.Provider = options.Parent.GetProvider(type); } } else { // If a provider was specified, add it to the providers map under this type's package so that // any children of this resource inherit its provider. var typeComponents = type.Split(":"); if (typeComponents.Length == 3) { var pkg = typeComponents[0]; this._providers = this._providers.SetItem(pkg, provider); } } } else { // Note: we checked above that at most one of options.provider or options.providers // is set. // If options.provider is set, treat that as if we were given a array of provider // with that single value in it. Otherwise, take the array of providers, convert it // to a map and combine with any providers we've already set from our parent. var providerList = options.Provider != null ? new List <ProviderResource> { options.Provider } : componentOpts?.Providers; this._providers = this._providers.AddRange(ConvertToProvidersMap(providerList)); } this._protect = options.Protect == true; this._provider = custom ? options.Provider : null; this._version = options.Version; // Collapse any 'Alias'es down to URNs. We have to wait until this point to do so // because we do not know the default 'name' and 'type' to apply until we are inside the // resource constructor. var aliases = ImmutableArray.CreateBuilder <Input <string> >(); foreach (var alias in options.Aliases) { aliases.Add(CollapseAliasToUrn(alias, name, type, options.Parent)); } this._aliases = aliases.ToImmutable(); Deployment.InternalInstance.ReadOrRegisterResource(this, remote, urn => new DependencyResource(urn), args, options); }
/// <summary> /// The AutoDevOps resource constructor, which takes care of deploying the whole thing /// </summary> /// <param name="settings">AutoDevOps settings, <see cref="AutoDevOpsSettings"/></param> /// <param name="sidecars">Optional: collection of sidecar containers</param> /// <param name="configureContainer">Optional: custom application container configuration</param> /// <param name="configurePod">Optional: custom pod configuration</param> /// <param name="configureDeployment">Optional: custom deployment configuration</param> /// <param name="configureService">Optional: custom service configuration</param> /// <param name="serviceAnnotations">Optional: service annotations</param> /// <param name="ingressAnnotations">Optional: ingress annotations</param> /// <param name="namespaceAnnotations">Optional: namespace annotations</param> /// <param name="deployExtras">Optional: use this to deploy other resources to the environment namespace, /// before the application is deployed.</param> /// <param name="provider">Optional: custom Kubernetes resource provider</param> public AutoDevOps( AutoDevOpsSettings settings, IEnumerable <ContainerArgs>?sidecars = null, Action <ContainerArgs>?configureContainer = null, Action <PodSpecArgs>?configurePod = null, Action <DeploymentArgs>?configureDeployment = null, Action <ServiceArgs>?configureService = null, Dictionary <string, string>?serviceAnnotations = null, Dictionary <string, string>?ingressAnnotations = null, Dictionary <string, string>?namespaceAnnotations = null, Action <Namespace>?deployExtras = null, ProviderResource?provider = null ) { var @namespace = KubeNamespace.Create(settings.Deploy.Namespace, namespaceAnnotations, provider); var namespaceName = @namespace.Metadata.Apply(x => x.Name); deployExtras?.Invoke(@namespace); var imagePullSecret = settings.GitLab.Visibility != "public" && settings.Registry != null ? KubeSecret.CreateRegistrySecret(namespaceName, settings.Registry, provider) : null; var replicas = settings.Deploy.Percentage > 0 || settings.Deploy.Replicas == 0 ? GetReplicas(settings.Application.Track, settings.Deploy.Percentage) : settings.Deploy.Replicas; if (replicas == 0) { DeploymentResult = new Result { Namespace = @namespace }; return; } var appSecret = KubeSecret.CreateAppSecret(namespaceName, settings, provider); var deployment = KubeDeployment.Create( namespaceName, settings, replicas, imagePullSecret, appSecret, sidecars, configureContainer, configurePod, configureDeployment, provider ); var service = settings.Service.Enabled ? KubeService.Create( namespaceName, settings, deployment, serviceAnnotations, configureService, provider ) : null; var ingress = settings.Ingress.Enabled && !settings.Deploy.Url.IsEmpty() ? KubeIngress.Create(namespaceName, settings, settings.Ingress.Class, ingressAnnotations, provider) : null; if (settings.Prometheus.Metrics && settings.Prometheus.Operator) { if (service != null) { Prometheus.CreateServiceMonitor(settings, service, @namespace, provider); } else { Prometheus.CreatePodMonitor(settings, deployment, @namespace, provider); } } DeploymentResult = new Result { Namespace = @namespace, Deployment = deployment, Service = service, Ingress = ingress }; }
public static RoleBinding AddJaeger( Namespace kubeNamespace, string jaegerNamespace = "observability", ProviderResource?providerResource = null) => new(