UNPKG

@hashgraph/solo

Version:

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

215 lines (186 loc) 8.09 kB
// SPDX-License-Identifier: Apache-2.0 import * as k8s from '@kubernetes/client-node'; import {type K8} from '../k8.js'; import {type Namespaces} from '../../../types/namespace/namespaces.js'; import {K8ClientClusters} from './resources/cluster/k8-client-clusters.js'; import {type Clusters} from '../resources/cluster/clusters.js'; import {type ConfigMaps} from '../resources/config-map/config-maps.js'; import {K8ClientConfigMaps} from './resources/config-map/k8-client-config-maps.js'; import {K8ClientContainers} from './resources/container/k8-client-containers.js'; import {type Containers} from '../resources/container/containers.js'; import {type Contexts} from '../resources/context/contexts.js'; import {K8ClientContexts} from './resources/context/k8-client-contexts.js'; import {K8ClientPods} from './resources/pod/k8-client-pods.js'; import {type Pods} from '../resources/pod/pods.js'; import {type Services} from '../resources/service/services.js'; import {K8ClientServices} from './resources/service/k8-client-services.js'; import {type Pvcs} from '../resources/pvc/pvcs.js'; import {K8ClientPvcs} from './resources/pvc/k8-client-pvcs.js'; import {type Leases} from '../resources/lease/leases.js'; import {K8ClientLeases} from './resources/lease/k8-client-leases.js'; import {K8ClientNamespaces} from './resources/namespace/k8-client-namespaces.js'; import {K8ClientIngressClasses} from './resources/ingress-class/k8-client-ingress-classes.js'; import {type IngressClasses} from '../resources/ingress-class/ingress-classes.js'; import {type Secrets} from '../resources/secret/secrets.js'; import {K8ClientSecrets} from './resources/secret/k8-client-secrets.js'; import {type Ingresses} from '../resources/ingress/ingresses.js'; import {K8ClientIngresses} from './resources/ingress/k8-client-ingresses.js'; import {type Crds} from '../resources/crd/crds.js'; import {K8ClientCrds} from './resources/crd/k8-client-crds.js'; import {KubeConfig} from '@kubernetes/client-node'; import {MissingActiveClusterError} from '../errors/missing-active-cluster-error.js'; import {MissingActiveContextError} from '../errors/missing-active-context-error.js'; import {type Optional} from '../../../types/index.js'; import {K8ClientManifests} from './resources/manifest/k8-client-manifests.js'; import {type Rbacs} from '../resources/rbac/rbacs.js'; import {K8ClientRbacs} from './resources/rbac/k8-client-rbacs.js'; import {NoKubeConfigContextError} from '../../../business/runtime-state/errors/no-kube-config-context-error.js'; /** * A kubernetes API wrapper class providing custom functionalities required by solo * * Note: Take care if the same instance is used for parallel execution, as the behaviour may be unpredictable. * For parallel execution, create separate instances by invoking clone() */ export class K8Client implements K8 { private kubeConfig!: k8s.KubeConfig; private kubeClient!: k8s.CoreV1Api; private coordinationApiClient!: k8s.CoordinationV1Api; private extensionApi!: k8s.ApiextensionsV1Api; private networkingApi!: k8s.NetworkingV1Api; private rbacApi!: k8s.RbacAuthorizationV1Api; private k8sObjectApi!: k8s.KubernetesObjectApi; private k8Leases: Leases; private k8Clusters: Clusters; private k8ConfigMaps: ConfigMaps; private k8Containers: Containers; private k8Pods: Pods; private k8Contexts: Contexts; private k8Services: Services; private k8Pvcs: Pvcs; private k8Namespaces: Namespaces; private k8IngressClasses: IngressClasses; private k8Secrets: Secrets; private k8Ingresses: Ingresses; private k8Crds: Crds; private k8Rbacs: Rbacs; private k8Manifests: K8ClientManifests; /** * Create a new k8Factory client for the given context, if context is undefined it will use the current context in kubeconfig * @param context - The context to create the k8Factory client for * @param kubectlInstallationDirectory - Path to executable of kubectl */ public constructor( private readonly context: string, private readonly kubectlInstallationDirectory: string, ) { this.init(this.context); } // TODO make private, but first we need to require a cluster to be set and address the test cases using this public init(context: Optional<string> = undefined): K8 { this.kubeConfig = this.getKubeConfig(context); if (!this.kubeConfig.getCurrentContext()) { throw new MissingActiveContextError(); } if (!this.kubeConfig.getCurrentCluster()) { throw new MissingActiveClusterError(); } this.kubeClient = this.kubeConfig.makeApiClient(k8s.CoreV1Api); this.networkingApi = this.kubeConfig.makeApiClient(k8s.NetworkingV1Api); this.coordinationApiClient = this.kubeConfig.makeApiClient(k8s.CoordinationV1Api); this.extensionApi = this.kubeConfig.makeApiClient(k8s.ApiextensionsV1Api); this.rbacApi = this.kubeConfig.makeApiClient(k8s.RbacAuthorizationV1Api); this.k8sObjectApi = this.kubeConfig.makeApiClient(k8s.KubernetesObjectApi); this.k8Clusters = new K8ClientClusters(this.kubeConfig); this.k8ConfigMaps = new K8ClientConfigMaps(this.kubeClient); this.k8Contexts = new K8ClientContexts(this.kubeConfig); this.k8Services = new K8ClientServices(this.kubeClient); this.k8Pods = new K8ClientPods(this.kubeClient, this.kubeConfig, this.kubectlInstallationDirectory); this.k8Containers = new K8ClientContainers(this.kubeConfig, this.k8Pods, this.kubectlInstallationDirectory); this.k8Pvcs = new K8ClientPvcs(this.kubeClient); this.k8Leases = new K8ClientLeases(this.coordinationApiClient); this.k8Namespaces = new K8ClientNamespaces(this.kubeClient); this.k8IngressClasses = new K8ClientIngressClasses(this.networkingApi); this.k8Secrets = new K8ClientSecrets(this.kubeClient); this.k8Ingresses = new K8ClientIngresses(this.networkingApi); this.k8Crds = new K8ClientCrds(this.extensionApi); this.k8Rbacs = new K8ClientRbacs(this.rbacApi); this.k8Manifests = new K8ClientManifests(this.k8sObjectApi); return this; } private getKubeConfig(context: string): KubeConfig { const kubeConfig: KubeConfig = new KubeConfig(); try { kubeConfig.loadFromDefault(); if (context) { if (!kubeConfig.getContextObject(context)) { throw new NoKubeConfigContextError(`No kube config context found with name ${context}`); } kubeConfig.setCurrentContext(context); } } catch (error) { if (process.env.KUBERNETES_SERVICE_HOST) { //* Try loading from cluster if loading from default fails try { kubeConfig.loadFromCluster(); } catch (fromClusterError) { throw new NoKubeConfigContextError( 'Failed to load Kubernetes configuration from cluster', fromClusterError, error, ); } } else { throw new NoKubeConfigContextError('Failed to load Kubernetes configuration from default location', error); } } return kubeConfig; } public namespaces(): Namespaces { return this.k8Namespaces; } public clusters(): Clusters { return this.k8Clusters; } public configMaps(): ConfigMaps { return this.k8ConfigMaps; } public containers(): Containers { return this.k8Containers; } public contexts(): Contexts { return this.k8Contexts; } public services(): Services { return this.k8Services; } public pods(): Pods { return this.k8Pods; } public pvcs(): Pvcs { return this.k8Pvcs; } public leases(): Leases { return this.k8Leases; } public secrets(): Secrets { return this.k8Secrets; } public ingressClasses(): IngressClasses { return this.k8IngressClasses; } public ingresses(): Ingresses { return this.k8Ingresses; } public crds(): Crds { return this.k8Crds; } public rbac(): Rbacs { return this.k8Rbacs; } public manifests(): K8ClientManifests { return this.k8Manifests; } public getKubectlExecutablePath(): string { return this.kubectlInstallationDirectory; } }