/// <inheritdoc/> public override async Task RunAsync(CommandLine commandLine) { if (commandLine.Arguments.Length < 1) { Console.Error.WriteLine("*** ERROR: [root@CLUSTER-NAME] argument is required."); Program.Exit(1); } Console.WriteLine(); // Cluster prepare/setup uses the [ProfileClient] to retrieve secrets and profile values. // We need to inject an implementation for [PreprocessReader] so it will be able to // perform the lookups. NeonHelper.ServiceContainer.AddSingleton <IProfileClient>(new ProfileClient()); var contextName = KubeContextName.Parse(commandLine.Arguments[0]); var kubeCluster = KubeHelper.Config.GetCluster(contextName.Cluster); var unredacted = commandLine.HasOption("--unredacted"); var debug = commandLine.HasOption("--debug"); var check = commandLine.HasOption("--check"); var uploadCharts = commandLine.HasOption("--upload-charts") || debug; var clusterspace = commandLine.GetOption("--clusterspace"); var maxParallelOption = commandLine.GetOption("--max-parallel", "6"); var disablePending = commandLine.HasOption("--disable-pending"); if (!int.TryParse(maxParallelOption, out var maxParallel) || maxParallel <= 0) { Console.Error.WriteLine($"*** ERROR: [--max-parallel={maxParallelOption}] is not valid."); Program.Exit(1); } clusterLogin = KubeHelper.GetClusterLogin(contextName); if (clusterLogin == null) { Console.Error.WriteLine($"*** ERROR: Be sure to prepare the cluster first via: neon cluster prepare..."); Program.Exit(1); } if (string.IsNullOrEmpty(clusterLogin.SshPassword)) { Console.Error.WriteLine($"*** ERROR: No cluster node SSH password found."); Program.Exit(1); } if (kubeCluster != null && !clusterLogin.SetupDetails.SetupPending) { if (commandLine.GetOption("--force") == null && !Program.PromptYesNo($"One or more logins reference [{kubeCluster.Name}]. Do you wish to delete these?")) { Program.Exit(0); } // Remove the cluster from the kubeconfig and remove any // contexts that reference it. KubeHelper.Config.Clusters.Remove(kubeCluster); var delList = new List <KubeConfigContext>(); foreach (var context in KubeHelper.Config.Contexts) { if (context.Properties.Cluster == kubeCluster.Name) { delList.Add(context); } } foreach (var context in delList) { KubeHelper.Config.Contexts.Remove(context); } if (KubeHelper.CurrentContext != null && KubeHelper.CurrentContext.Properties.Cluster == kubeCluster.Name) { KubeHelper.Config.CurrentContext = null; } KubeHelper.Config.Save(); } kubeContext = new KubeConfigContext(contextName); KubeHelper.InitContext(kubeContext); // Create and run the cluster setup controller. var clusterDefinition = clusterLogin.ClusterDefinition; var controller = KubeSetup.CreateClusterSetupController( clusterDefinition, maxParallel: maxParallel, unredacted: unredacted, debugMode: debug, uploadCharts: uploadCharts, clusterspace: clusterspace); controller.DisablePendingTasks = disablePending; controller.StatusChangedEvent += status => { status.WriteToConsole(); }; switch (await controller.RunAsync()) { case SetupDisposition.Succeeded: var pendingGroups = controller.GetPendingGroups(); if (pendingGroups.Count > 0) { Console.WriteLine($"*** ERROR: [{pendingGroups.Count}] pending task groups have not been awaited:"); Console.WriteLine(); foreach (var groupName in pendingGroups) { Console.WriteLine($" {groupName}"); } Program.Exit(1); } Console.WriteLine(); Console.WriteLine($" [{clusterDefinition.Name}] cluster is ready."); Console.WriteLine(); if (check && !debug) { var k8s = new Kubernetes(KubernetesClientConfiguration.BuildConfigFromConfigFile(KubeHelper.KubeConfigPath)); if (!await ClusterChecker.CheckAsync(clusterLogin, k8s)) { Program.Exit(1); } } Program.Exit(0); break; case SetupDisposition.Cancelled: Console.WriteLine(" *** CANCELLED: Cluster setup was cancelled."); Console.WriteLine(); Console.WriteLine(); Program.Exit(1); break; case SetupDisposition.Failed: Console.WriteLine(); Console.WriteLine(" *** ERROR: Cluster setup failed. Examine the logs here:"); Console.WriteLine(); Console.WriteLine($" {KubeHelper.LogFolder}"); Console.WriteLine(); Program.Exit(1); break; default: throw new NotImplementedException(); } await Task.CompletedTask; }