Skip to content

Commit 6afa050

Browse files
committed
created factory and way to get k8 instance passing in the context
Signed-off-by: Jeromy Cannon <[email protected]>
1 parent d77f122 commit 6afa050

File tree

4 files changed

+97
-16
lines changed

4 files changed

+97
-16
lines changed

src/core/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ export const TREASURY_ACCOUNT = 2;
103103
export const LOCAL_NODE_START_PORT = +process.env.LOCAL_NODE_START_PORT || 30212;
104104
export const ACCOUNT_UPDATE_BATCH_SIZE = +process.env.ACCOUNT_UPDATE_BATCH_SIZE || 10;
105105

106+
/**
107+
* The default K8 instance name that will use the kubeconfig current context
108+
*/
109+
export const K8_DEFAULT_INSTANCE = 'DEFAULT';
110+
106111
export const POD_PHASE_RUNNING = 'Running';
107112

108113
export const POD_CONDITION_INITIALIZED = 'Initialized';

src/core/kube/k8_client/k8_client.ts

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import * as k8s from '@kubernetes/client-node';
55
import {SoloError} from '../../errors.js';
66
import {type ConfigManager} from '../../config_manager.js';
77
import {type SoloLogger} from '../../logging.js';
8-
import {inject, injectable} from 'tsyringe-neo';
9-
import {patchInject} from '../../dependency_injection/container_helper.js';
8+
import {container} from 'tsyringe-neo';
109
import {type K8} from '../k8.js';
1110
import {type Namespaces} from '../resources/namespace/namespaces.js';
1211
import {K8ClientClusters} from '../k8_client/resources/cluster/k8_client_clusters.js';
@@ -16,7 +15,6 @@ import {K8ClientConfigMaps} from '../k8_client/resources/config_map/k8_client_co
1615
import {K8ClientContainers} from '../k8_client/resources/container/k8_client_containers.js';
1716
import {type Containers} from '../resources/container/containers.js';
1817
import {type Contexts} from '../resources/context/contexts.js';
19-
import {K8ClientContexts} from '../k8_client/resources/context/k8_client_contexts.js';
2018
import {K8ClientPods} from '../k8_client/resources/pod/k8_client_pods.js';
2119
import {type Pods} from '../resources/pod/pods.js';
2220
import {type Services} from '../resources/service/services.js';
@@ -33,14 +31,14 @@ import {K8ClientSecrets} from '../k8_client/resources/secret/k8_client_secrets.j
3331
import {type Ingresses} from '../resources/ingress/ingresses.js';
3432
import {K8ClientIngresses} from './resources/ingress/k8_client_ingresses.js';
3533
import {InjectTokens} from '../../dependency_injection/inject_tokens.js';
34+
import * as constants from '../../constants.js';
3635

3736
/**
3837
* A kubernetes API wrapper class providing custom functionalities required by solo
3938
*
4039
* Note: Take care if the same instance is used for parallel execution, as the behaviour may be unpredictable.
4140
* For parallel execution, create separate instances by invoking clone()
4241
*/
43-
@injectable()
4442
export class K8Client implements K8 {
4543
private kubeConfig!: k8s.KubeConfig;
4644
private kubeClient!: k8s.CoreV1Api;
@@ -60,20 +58,19 @@ export class K8Client implements K8 {
6058
private k8Secrets: Secrets;
6159
private k8Ingresses: Ingresses;
6260

63-
constructor(
64-
@inject(InjectTokens.ConfigManager) private readonly configManager?: ConfigManager,
65-
@inject(InjectTokens.SoloLogger) private readonly logger?: SoloLogger,
66-
) {
67-
this.configManager = patchInject(configManager, InjectTokens.ConfigManager, this.constructor.name);
68-
this.logger = patchInject(logger, InjectTokens.SoloLogger, this.constructor.name);
61+
private readonly configManager: ConfigManager;
62+
private readonly logger: SoloLogger;
6963

70-
this.init();
64+
constructor(private readonly context: string) {
65+
this.configManager = container.resolve(InjectTokens.ConfigManager);
66+
this.logger = container.resolve(InjectTokens.SoloLogger);
67+
68+
this.init(context);
7169
}
7270

7371
// TODO make private, but first we need to require a cluster to be set and address the test cases using this
74-
init(): K8 {
75-
this.kubeConfig = new k8s.KubeConfig();
76-
this.kubeConfig.loadFromDefault();
72+
init(context: string = undefined): K8 {
73+
this.kubeConfig = this.getKubeConfig(context);
7774

7875
if (!this.kubeConfig.getCurrentContext()) {
7976
throw new SoloError('No active kubernetes context found. ' + 'Please set current kubernetes context.');
@@ -89,7 +86,6 @@ export class K8Client implements K8 {
8986

9087
this.k8Clusters = new K8ClientClusters(this.kubeConfig);
9188
this.k8ConfigMaps = new K8ClientConfigMaps(this.kubeClient);
92-
this.k8Contexts = new K8ClientContexts(this.kubeConfig);
9389
this.k8Services = new K8ClientServices(this.kubeClient);
9490
this.k8Pods = new K8ClientPods(this.kubeClient, this.kubeConfig);
9591
this.k8Containers = new K8ClientContainers(this.kubeConfig, this.k8Pods);
@@ -100,7 +96,34 @@ export class K8Client implements K8 {
10096
this.k8Secrets = new K8ClientSecrets(this.kubeClient);
10197
this.k8Ingresses = new K8ClientIngresses(this.networkingApi);
10298

103-
return this; // to enable chaining
99+
// TODO this will run in the background, change this to use an await somehow, possibly after init is made private
100+
this.contexts()
101+
.testContextConnection(this.kubeConfig.getCurrentContext())
102+
.then(() => {
103+
this.logger.info(`successfully established connection to context: ${this.kubeConfig.getCurrentContext()}`);
104+
})
105+
.catch(e => {
106+
const message = `Failed to create a connect to the K8 context '${this.kubeConfig.getCurrentContext()}'`;
107+
this.logger.error(message, e);
108+
throw new SoloError(message, e);
109+
});
110+
111+
return this;
112+
}
113+
114+
private getKubeConfig(context: string): k8s.KubeConfig {
115+
const kubeConfig = new k8s.KubeConfig();
116+
kubeConfig.loadFromDefault();
117+
118+
if (context !== constants.K8_DEFAULT_INSTANCE) {
119+
const kubeConfigContext: k8s.Context = kubeConfig.getContextObject(context);
120+
if (!kubeConfigContext) {
121+
throw new SoloError(`No kube config context found with name ${context}`);
122+
}
123+
kubeConfig.setCurrentContext(context);
124+
}
125+
126+
return kubeConfig;
104127
}
105128

106129
public namespaces(): Namespaces {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
import {type K8Factory} from '../k8_factory.js';
5+
import {type K8} from '../k8.js';
6+
import {K8Client} from './k8_client.js';
7+
import * as constants from '../../constants.js';
8+
9+
@injectable()
10+
export class K8ClientFactory implements K8Factory {
11+
private readonly k8Clients: Map<string, K8> = new Map<string, K8>();
12+
13+
/**
14+
* Get a k8 instance for the given context. Provide constants.K8_DEFAULT_INSTANCE to get the default instance which
15+
* uses the kubeconfig current context
16+
* @param context - The context to get the k8 instance for
17+
* @returns a k8 instance
18+
*/
19+
public getK8(context: string): K8 {
20+
if (!this.k8Clients.has(context)) {
21+
this.k8Clients.set(context, this.createK8Client(context));
22+
}
23+
24+
return this.k8Clients.get(context)!;
25+
}
26+
27+
/**
28+
* Create a new k8 client for the given context, if it is constants.K8_DEFAULT_INSTANCE, then it will return an
29+
* instance with kube configs current context
30+
* @param context - The context to create the k8 client for
31+
* @returns a new k8 client
32+
* @private
33+
*/
34+
private createK8Client(context: string): K8 {
35+
if (context === constants.K8_DEFAULT_INSTANCE) {
36+
return new K8Client(undefined);
37+
} else {
38+
return new K8Client(context);
39+
}
40+
}
41+
}

src/core/kube/k8_factory.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
import {type K8} from './k8.js';
5+
6+
export interface K8Factory {
7+
/**
8+
* Get a k8 instance for the given context
9+
* @param context - The context to get the k8 instance for
10+
*/
11+
getK8(context: string): K8;
12+
}

0 commit comments

Comments
 (0)