/// <summary> /// <para> /// Ensures that <b>helm</b> tool whose version is at least as great as the requested /// cluster version is installed to the <b>neonKUBE</b> programs folder by copying the /// tool from the cache if necessary. /// </para> /// <note> /// This will probably require elevated privileges. /// </note> /// <note> /// This assumes that <b>Helm</b> has already been downloaded and cached and also that /// more recent <b>Helm</b> releases are backwards compatible with older deployed versions /// of Tiller. /// </note> /// </summary> /// <param name="setupInfo">The KUbernetes setup information.</param> public static void InstallHelm(KubeSetupInfo setupInfo) { Covenant.Requires <ArgumentNullException>(setupInfo != null); var hostPlatform = KubeHelper.HostPlatform; var cachedHelmPath = KubeHelper.GetCachedComponentPath(hostPlatform, "helm", setupInfo.Versions.Helm); var targetPath = Path.Combine(KubeHelper.ProgramFolder); switch (hostPlatform) { case KubeHostPlatform.Windows: targetPath = Path.Combine(targetPath, "helm.exe"); if (!File.Exists(targetPath)) { File.Copy(cachedHelmPath, targetPath); } else { // Execute the existing target to obtain its version and update it // to the cached copy if the cluster installed a more recent version // of Kubernetes. // $hack(jeff.lill): Simple client version extraction var pattern = "SemVer:\"v"; var response = NeonHelper.ExecuteCapture(targetPath, "version"); var pStart = response.OutputText.IndexOf(pattern); var error = "Cannot identify existing [helm] version."; if (pStart == -1) { throw new KubeException(error); } pStart += pattern.Length; var pEnd = response.OutputText.IndexOf("\"", pStart); if (pEnd == -1) { throw new KubeException(error); } var currentVersionString = response.OutputText.Substring(pStart, pEnd - pStart); if (!Version.TryParse(currentVersionString, out var currentVersion)) { throw new KubeException(error); } if (Version.Parse(setupInfo.Versions.Helm) > currentVersion) { // We need to copy the latest version. File.Copy(cachedHelmPath, targetPath); } } break; case KubeHostPlatform.Linux: case KubeHostPlatform.Osx: default: throw new NotImplementedException($"[{hostPlatform}] support is not implemented."); } }
/// <summary> /// <para> /// Ensures that <b>kubectl</b> tool whose version is at least as great as the Kubernetes /// cluster version is installed to the <b>neonKUBE</b> programs folder by copying the /// tool from the cache if necessary. /// </para> /// <note> /// This will probably require elevated privileges. /// </note> /// <note> /// This assumes that <b>kubectl</b> has already been downloaded and cached and also that /// more recent <b>kubectl</b> releases are backwards compatible with older deployed versions /// of Kubernetes. /// </note> /// </summary> /// <param name="setupInfo">The KUbernetes setup information.</param> public static void InstallKubeCtl(KubeSetupInfo setupInfo) { Covenant.Requires <ArgumentNullException>(setupInfo != null); var hostPlatform = KubeHelper.HostPlatform; var cachedKubeCtlPath = KubeHelper.GetCachedComponentPath(hostPlatform, "kubectl", setupInfo.Versions.Kubernetes); var targetPath = Path.Combine(KubeHelper.ProgramFolder); switch (hostPlatform) { case KubeHostPlatform.Windows: targetPath = Path.Combine(targetPath, "kubectl.exe"); // Ensure that the KUBECONFIG environment variable exists and includes // the path to the user's [.neonkube] configuration. var kubeConfigVar = Environment.GetEnvironmentVariable("KUBECONFIG"); if (string.IsNullOrEmpty(kubeConfigVar)) { // The [KUBECONFIG] environment variable doesn't exist so we'll set it. Registry.SetValue(@"HKEY_CURRENT_USER\Environment", "KUBECONFIG", KubeConfigPath, RegistryValueKind.ExpandString); Environment.SetEnvironmentVariable("KUBECONFIG", KubeConfigPath); } else { // The [KUBECONFIG] environment variable exists but we still need to // ensure that the path to our [USER/.neonkube] config is present. var sb = new StringBuilder(); var found = false; foreach (var path in kubeConfigVar.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { if (path == KubeConfigPath) { found = true; } sb.AppendWithSeparator(path, ";"); } if (!found) { sb.AppendWithSeparator(KubeConfigPath, ";"); } var newKubeConfigVar = sb.ToString(); if (newKubeConfigVar != kubeConfigVar) { Registry.SetValue(@"HKEY_CURRENT_USER\Environment", "KUBECONFIG", newKubeConfigVar, RegistryValueKind.ExpandString); Environment.SetEnvironmentVariable("KUBECONFIG", newKubeConfigVar); } } if (!File.Exists(targetPath)) { File.Copy(cachedKubeCtlPath, targetPath); } else { // Execute the existing target to obtain its version and update it // to the cached copy if the cluster installed a more recent version // of Kubernetes. // $hack(jeff.lill): Simple client version extraction var pattern = "GitVersion:\"v"; var response = NeonHelper.ExecuteCapture(targetPath, "version"); var pStart = response.OutputText.IndexOf(pattern); var error = "Cannot identify existing [kubectl] version."; if (pStart == -1) { throw new KubeException(error); } pStart += pattern.Length; var pEnd = response.OutputText.IndexOf("\"", pStart); if (pEnd == -1) { throw new KubeException(error); } var currentVersionString = response.OutputText.Substring(pStart, pEnd - pStart); if (!Version.TryParse(currentVersionString, out var currentVersion)) { throw new KubeException(error); } if (Version.Parse(setupInfo.Versions.Kubernetes) > currentVersion) { // We need to copy the latest version. if (File.Exists(targetPath)) { File.Delete(targetPath); } File.Copy(cachedKubeCtlPath, targetPath); } } break; case KubeHostPlatform.Linux: case KubeHostPlatform.Osx: default: throw new NotImplementedException($"[{hostPlatform}] support is not implemented."); } }