UNPKG

@hashgraph/solo

Version:

An opinionated CLI tool to deploy and manage private Hedera Networks.

101 lines (92 loc) 4.08 kB
// SPDX-License-Identifier: Apache-2.0 import * as constants from '../constants.js'; import * as version from '../../../version.js'; import {inject, injectable} from 'tsyringe-neo'; import {patchInject} from '../dependency-injection/container-helper.js'; import {InjectTokens} from '../dependency-injection/inject-tokens.js'; import {BaseDependencyManager} from './base-dependency-manager.js'; import {PackageDownloader} from '../package-downloader.js'; import {format} from 'node:util'; import {SoloError} from '../errors/solo-error.js'; import {OperatingSystem} from '../../business/utils/operating-system.js'; const KUBECTL_RELEASE_BASE_URL: string = 'https://dl.k8s.io/release'; const KUBECTL_ARTIFACT_TEMPLATE: string = '%s/bin/%s/%s/kubectl'; const KUBECTL_WINDOWS_ARTIFACT_TEMPLATE: string = '%s/bin/%s/%s/kubectl.exe'; @injectable() export class KubectlDependencyManager extends BaseDependencyManager { public constructor( @inject(InjectTokens.PackageDownloader) downloader: PackageDownloader, @inject(InjectTokens.KubectlInstallationDirectory) installationDirectory: string, @inject(InjectTokens.OsArch) osArch: string, @inject(InjectTokens.KubectlVersion) kubectlVersion: string, ) { // Call the base constructor with the Kubectl-specific parameters super( patchInject(downloader, InjectTokens.PackageDownloader, KubectlDependencyManager.name), patchInject(installationDirectory, InjectTokens.KubectlInstallationDirectory, KubectlDependencyManager.name), patchInject(osArch, InjectTokens.OsArch, KubectlDependencyManager.name), patchInject(kubectlVersion, InjectTokens.KubectlVersion, KubectlDependencyManager.name) || version.KUBECTL_VERSION, constants.KUBECTL, KUBECTL_RELEASE_BASE_URL, ); } /** * Get the Kubectl artifact name based on version, OS, and architecture */ protected getArtifactName(): string { return format( OperatingSystem.isWin32() ? KUBECTL_WINDOWS_ARTIFACT_TEMPLATE : KUBECTL_ARTIFACT_TEMPLATE, this.getRequiredVersion(), OperatingSystem.getFormattedPlatform(), this.osArch, ); } public async getVersion(executableWithPath: string): Promise<string> { try { // Override KUBECONFIG to prevent loading kubeconfig and triggering authentication // plugins (e.g., Teleport exec credentials) which can hang in non-interactive environments. // Using the null device ensures kubectl only reports the client version without any // server or credential-related operations. const nullDevice: string = OperatingSystem.isWin32() ? 'nul' : '/dev/null'; const output: string[] = await this.run( `"${executableWithPath}" version --client`, [], false, false, {KUBECONFIG: nullDevice}, 30_000, ); this.logger.debug(`Raw kubectl version output: ${output.join('\n')}`); if (output.length > 0) { for (const line of output) { if (line.trim().startsWith('Client Version')) { const match: RegExpMatchArray | null = line.trim().match(/(\d+\.\d+\.\d+)/); if (match) { const detectedVersion: string = match[1]; this.logger.info(`Kubectl version: ${detectedVersion}`); return detectedVersion; } } } } } catch (error) { throw new SoloError('Failed to check kubectl version', error); } throw new SoloError('Failed to get kubectl version'); } protected getDownloadURL(): string { return `${this.downloadBaseUrl}/${this.artifactName}`; } /** * Handle any post-download processing before copying to destination * Child classes can override this for custom extraction or processing */ protected async processDownloadedPackage(packageFilePath: string): Promise<string[]> { // For kubectl, the downloaded file is the executable itself, so we can return it directly return [packageFilePath]; } protected getChecksumURL(): string { return `${this.downloadURL}.sha256`; } }