/// <summary> /// Configures depdendency injection. /// </summary> /// <param name="services">The service collection.</param> public void ConfigureServices(IServiceCollection services) { // $hack(jefflill): // // This will be called when CRDs and other assets are being generated by KubeOps // and also when the service is actually being started. We need to load the // [WATCHER_MAX_RETRY_INTERVAL] environment variable. Unfortunately, [Program.Service] // won't be set when generating CRDs, so we'll just set a default value. var watcherTimeout = TimeSpan.FromMinutes(2); var watcherRetry = TimeSpan.FromSeconds(15); if (Program.Service != null) { watcherTimeout = Program.Service.Environment.Get("WATCHER_TIMEOUT_INTERVAL", watcherTimeout); watcherRetry = Program.Service.Environment.Get("WATCHER_MAX_RETRY_INTERVAL", watcherRetry); } var watcherTimeoutSeconds = Math.Max(1, Math.Max(ushort.MaxValue, (int)Math.Ceiling(watcherTimeout.TotalSeconds))); var watcherRetrySeconds = Math.Max(1, (int)Math.Ceiling(watcherTimeout.TotalSeconds)); var k8s = OperatorHelper.GeneratingCRDs ? KubernetesWithRetry.CreateDisconnected() : new KubernetesWithRetry(KubernetesClientConfiguration.BuildDefaultConfig()); var operatorBuilder = services .AddSingleton(k8s) .AddKubernetesOperator( settings => { settings.EnableAssemblyScanning = true; settings.EnableLeaderElection = false; // ResourceManager is managing leader election settings.WatcherHttpTimeout = (ushort)watcherTimeoutSeconds; settings.WatcherMaxRetrySeconds = watcherRetrySeconds; }); Program.AddResourceAssemblies(operatorBuilder); }
/// <summary> /// Constructor /// </summary> /// <param name="jsonClient">The JSON client for interacting with the headend.</param> public AcmeController( Service service, JsonClient jsonClient) { this.service = service; this.jsonClient = jsonClient; this.k8s = service.Kubernetes; }
/// <inheritdoc/> protected async override Task <int> OnRunAsync() { await SetStatusAsync(NeonServiceStatus.Starting); Kubernetes = new KubernetesWithRetry(KubernetesClientConfiguration.BuildDefaultConfig()); // Start the web service. var port = 443; if (NeonHelper.IsDevWorkstation) { port = 11004; } webHost = new WebHostBuilder() .ConfigureAppConfiguration( (hostingcontext, config) => { config.Sources.Clear(); }) .UseStartup <Startup>() .UseKestrel(options => { options.Listen(IPAddress.Any, port, listenOptions => { if (!NeonHelper.IsDevWorkstation) { listenOptions.UseHttps(X509Certificate2.CreateFromPem( File.ReadAllText(@"/tls/tls.crt"), File.ReadAllText(@"/tls/tls.key"))); } }); }) .ConfigureServices(services => services.AddSingleton(typeof(Service), this)) .UseStaticWebAssets() .Build(); _ = webHost.RunAsync(); Log.LogInfo($"Listening on {IPAddress.Any}:{port}"); // Indicate that the service is ready for business. await SetStatusAsync(NeonServiceStatus.Running); // Handle termination gracefully. await Terminator.StopEvent.WaitAsync(); Terminator.ReadyToExit(); return(0); }
/// <summary> /// Constructor. /// </summary> /// <param name="configuration">Specifies the service configuration.</param> /// <param name="service">Specifies the service.</param> public Startup(IConfiguration configuration, Service service) { Configuration = configuration; this.NeonDashboardService = service; k8s = service.Kubernetes; }
/// <inheritdoc/> protected async override Task <int> OnRunAsync() { await SetStatusAsync(NeonServiceStatus.Starting); var port = 80; Kubernetes = new KubernetesWithRetry(KubernetesClientConfiguration.BuildDefaultConfig()); _ = Kubernetes.WatchAsync <V1ConfigMap>(async(@event) => { await SyncContext.Clear; ClusterInfo = TypeSafeConfigMap <ClusterInfo> .From(@event.Value).Config; Log.LogInfo($"Updated cluster info"); }, KubeNamespace.NeonStatus, fieldSelector: $"metadata.name={KubeConfigMapName.ClusterInfo}"); Dashboards = new List <Dashboard>(); Dashboards.Add( new Dashboard( id: "neonkube", name: "neonKUBE", displayOrder: 0)); _ = Kubernetes.WatchAsync <V1NeonDashboard>(async(@event) => { await SyncContext.Clear; switch (@event.Type) { case WatchEventType.Added: await AddDashboardAsync(@event.Value); break; case WatchEventType.Deleted: await RemoveDashboardAsync(@event.Value); break; case WatchEventType.Modified: await RemoveDashboardAsync(@event.Value); await AddDashboardAsync(@event.Value); break; default: break; } Dashboards = Dashboards.OrderBy(d => d.DisplayOrder) .ThenBy(d => d.Name).ToList(); }); if (NeonHelper.IsDevWorkstation) { port = 11001; SetEnvironmentVariable("LOG_LEVEL", "debug"); SetEnvironmentVariable("DO_NOT_TRACK", "true"); SetEnvironmentVariable("COOKIE_CIPHER", "/HwPfpfACC70Rh1DeiMdubHINQHRGfc4JP6DYcSkAQ8="); await ConfigureDevAsync(); } var metricsHost = GetEnvironmentVariable("METRICS_HOST", "http://mimir-query-frontend.neon-monitor.svc.cluster.local:8080"); PrometheusClient = new PrometheusClient($"{metricsHost}/prometheus/"); SsoClientSecret = GetEnvironmentVariable("SSO_CLIENT_SECRET", redacted: !Log.IsLogDebugEnabled); AesCipher = new AesCipher(GetEnvironmentVariable("COOKIE_CIPHER", AesCipher.GenerateKey(), redacted: !Log.IsLogDebugEnabled)); // Start the web service. webHost = new WebHostBuilder() .ConfigureAppConfiguration( (hostingcontext, config) => { config.Sources.Clear(); }) .UseStartup <Startup>() .UseKestrel(options => options.Listen(IPAddress.Any, port)) .ConfigureServices(services => services.AddSingleton(typeof(Service), this)) .UseStaticWebAssets() .Build(); _ = webHost.RunAsync(); Log.LogInfo($"Listening on {IPAddress.Any}:{port}"); // Indicate that the service is running. await StartedAsync(); // Handle termination gracefully. await Terminator.StopEvent.WaitAsync(); Terminator.ReadyToExit(); return(0); }