Skip to content

Commit 71388dd

Browse files
committed
pushing latest
Signed-off-by: Jeromy Cannon <[email protected]>
1 parent 209c2cd commit 71388dd

File tree

10 files changed

+122
-33
lines changed

10 files changed

+122
-33
lines changed

src/commands/base.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ export abstract class BaseCommand extends ShellRunner {
7272
return `${chartRepo}/${chartReleaseName}`;
7373
}
7474

75+
// TODO @Lenin, this is in the base so it will be used by everyone, which might be good because they won't have to duplicate the code
76+
// perhaps we should clone this method and have the new method return an object Record<ClusterRef, valuesFileArg>
77+
// need to support: --values-file aws-cluster=aws/solo-values.yaml,aws-cluster=aws/solo-values2.yaml,gcp-cluster=gcp/solo-values.yaml,gcp-cluster=gcp/solo-values2.yaml
7578
public prepareValuesFiles(valuesFile: string) {
7679
let valuesArg = '';
7780
if (valuesFile) {

src/commands/deployment.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {type SoloListrTask} from '../types/index.js';
1616
import {type Opts} from '../types/command_types.js';
1717
import {ErrorMessages} from '../core/error_messages.js';
1818
import {splitFlagInput} from '../core/helpers.js';
19-
import {type NamespaceName} from '../core/kube/resources/namespace/namespace_name.js';
19+
import {NamespaceName} from '../core/kube/resources/namespace/namespace_name.js';
2020
import {type ClusterChecks} from '../core/cluster_checks.js';
2121
import {container} from 'tsyringe-neo';
2222
import {InjectTokens} from '../core/dependency_injection/inject_tokens.js';
@@ -39,14 +39,15 @@ export class DeploymentCommand extends BaseCommand {
3939
flags.userEmailAddress,
4040
flags.deployment,
4141
flags.deploymentClusters,
42+
flags.nodeAliasesUnparsed,
4243
];
4344
}
4445

4546
private static get LIST_DEPLOYMENTS_FLAGS_LIST(): CommandFlag[] {
4647
return [flags.quiet, flags.clusterRef];
4748
}
4849

49-
private async create(argv: any): Promise<boolean> {
50+
public async create(argv: any): Promise<boolean> {
5051
const self = this;
5152

5253
interface Config {
@@ -57,6 +58,7 @@ export class DeploymentCommand extends BaseCommand {
5758
namespace: NamespaceName;
5859
deployment: DeploymentName;
5960
deploymentClusters: string[];
61+
nodeAliases: string[];
6062
}
6163

6264
interface Context {
@@ -82,6 +84,7 @@ export class DeploymentCommand extends BaseCommand {
8284
namespace: self.configManager.getFlag<NamespaceName>(flags.namespace),
8385
deployment: self.configManager.getFlag<DeploymentName>(flags.deployment),
8486
deploymentClusters: splitFlagInput(self.configManager.getFlag<string>(flags.deploymentClusters)),
87+
nodeAliases: splitFlagInput(self.configManager.getFlag<string>(flags.nodeAliasesUnparsed)),
8588
} as Config;
8689

8790
self.logger.debug('Prepared config', {config: ctx.config, cachedConfig: self.configManager.config});
@@ -93,7 +96,13 @@ export class DeploymentCommand extends BaseCommand {
9396
title: 'Add new deployment to local config',
9497
task: async (ctx, task) => {
9598
const {deployments} = this.localConfig;
96-
const {deployment, namespace, deploymentClusters} = ctx.config;
99+
const {deployment, namespace: configNamespace, deploymentClusters} = ctx.config;
100+
let namespace = configNamespace;
101+
if (!namespace?.name) {
102+
namespace = NamespaceName.of(deployment);
103+
ctx.config.namespace = namespace;
104+
this.configManager.setFlag(flags.namespace, namespace);
105+
}
97106
deployments[deployment] = {
98107
namespace: namespace.name,
99108
clusters: deploymentClusters,

src/commands/network.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ export class NetworkCommand extends BaseCommand {
159159
// Generating new minio credentials
160160
const envString = `MINIO_ROOT_USER=${minioAccessKey}\nMINIO_ROOT_PASSWORD=${minioSecretKey}`;
161161
minioData['config.env'] = Base64.encode(envString);
162+
// TODO: @Lenin, needs to run once for each cluster
162163
const isMinioSecretCreated = await this.k8Factory
163164
.default()
164165
.secrets()
@@ -192,6 +193,7 @@ export class NetworkCommand extends BaseCommand {
192193
cloudData['S3_SECRET_KEY'] = Base64.encode(minioSecretKey);
193194
}
194195

196+
// TODO: @Lenin, needs to run once for each cluster
195197
const isCloudSecretCreated = await this.k8Factory
196198
.default()
197199
.secrets()
@@ -206,6 +208,8 @@ export class NetworkCommand extends BaseCommand {
206208
const backupData = {};
207209
const googleCredential = fs.readFileSync(config.googleCredential, 'utf8');
208210
backupData['saJson'] = Base64.encode(googleCredential);
211+
212+
// TODO: @Lenin, needs to run once for each cluster
209213
const isBackupSecretCreated = await this.k8Factory
210214
.default()
211215
.secrets()
@@ -336,7 +340,10 @@ export class NetworkCommand extends BaseCommand {
336340
valuesArg += ' --set "defaults.envoyProxy.serviceType=LoadBalancer"';
337341
}
338342

343+
// TODO @Lenin, entrypoint for setting the values files,
339344
if (config.valuesFile) {
345+
// TODO: @Lenin, instead of adding it to the valuesArg, then create a copy of the valuesArg, one for each cluster, and append the
346+
// correct valuesFileArg to each valuesArg using the same argument structure as referenced above prepareValuesFiles
340347
valuesArg += this.prepareValuesFiles(config.valuesFile);
341348
}
342349

@@ -429,9 +436,6 @@ export class NetworkCommand extends BaseCommand {
429436
flags.genesisThrottlesFile.definition.defaultValue as string,
430437
);
431438

432-
config.valuesArg = await this.prepareValuesArg(config);
433-
config.namespace = namespace;
434-
435439
config.consensusNodes = this.getConsensusNodes();
436440
config.contexts = this.getContexts();
437441
if (config.nodeAliases.length === 0) {
@@ -441,6 +445,11 @@ export class NetworkCommand extends BaseCommand {
441445
}
442446
}
443447

448+
// TODO: @Lenin, maybe we should turn `config.valuesArg` into an object, Record<ClusterRef, valuesArg: string>
449+
config.valuesArg = await this.prepareValuesArg(config);
450+
config.namespace = namespace;
451+
452+
// TODO: @Lenin, will need to run once for each cluster
444453
if (!(await this.k8Factory.default().namespaces().has(namespace))) {
445454
await this.k8Factory.default().namespaces().create(namespace);
446455
}
@@ -536,8 +545,10 @@ export class NetworkCommand extends BaseCommand {
536545
{
537546
title: 'Check if cluster setup chart is installed',
538547
task: async () => {
548+
// TODO @Lenin, need to use the config.contexts for each isChartInstalled call
539549
const isChartInstalled = await this.chartManager.isChartInstalled(null, constants.SOLO_CLUSTER_SETUP_CHART);
540550
if (!isChartInstalled) {
551+
// TODO @Lenin, update error message
541552
throw new SoloError(
542553
`Chart ${constants.SOLO_CLUSTER_SETUP_CHART} is not installed. Run 'solo cluster setup'`,
543554
);
@@ -553,7 +564,7 @@ export class NetworkCommand extends BaseCommand {
553564
title: 'Copy Gossip keys to staging',
554565
task: ctx => {
555566
const config = ctx.config;
556-
567+
// TODO @Lenin, need to use consensusNodes instead of nodeAliases
557568
this.keyManager.copyGossipKeysToStaging(config.keysDir, config.stagingKeysDir, config.nodeAliases);
558569
},
559570
},

src/commands/node/handlers.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ export class NodeCommandHandlers implements CommandHandlers {
5353
private readonly tasks: NodeCommandTasks;
5454
private readonly leaseManager: LeaseManager;
5555
public readonly remoteConfigManager: RemoteConfigManager;
56-
public readonly contexts: string[];
57-
public readonly consensusNodes: ConsensusNode[];
56+
public contexts: string[];
57+
public consensusNodes: ConsensusNode[];
5858

5959
private getConfig: any;
6060
private prepareChartPath: any;
@@ -83,9 +83,6 @@ export class NodeCommandHandlers implements CommandHandlers {
8383
this.getConfig = opts.parent.getConfig.bind(opts.parent);
8484
this.prepareChartPath = opts.parent.prepareChartPath.bind(opts.parent);
8585

86-
this.consensusNodes = opts.parent.getConsensusNodes();
87-
this.contexts = opts.parent.getContexts();
88-
8986
this.parent = opts.parent;
9087
}
9188

@@ -94,6 +91,10 @@ export class NodeCommandHandlers implements CommandHandlers {
9491
static readonly UPDATE_CONTEXT_FILE = 'node-update.json';
9592
static readonly UPGRADE_CONTEXT_FILE = 'node-upgrade.json';
9693

94+
private init() {
95+
this.consensusNodes = this.parent.getConsensusNodes();
96+
this.contexts = this.parent.getContexts();
97+
}
9798
/** ******** Task Lists **********/
9899

99100
deletePrepareTaskList(argv: any, lease: Lease) {
@@ -742,6 +743,7 @@ export class NodeCommandHandlers implements CommandHandlers {
742743
}
743744

744745
async keys(argv: any) {
746+
this.init();
745747
argv = helpers.addFlagsToArgv(argv, NodeFlags.KEYS_FLAGS);
746748

747749
const action = this.parent.commandActionBuilder(

src/core/config/remote/components_data_wrapper.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* SPDX-License-Identifier: Apache-2.0
33
*/
4-
import {ComponentType} from './enumerations.js';
4+
import {ComponentType, ConsensusNodeStates} from './enumerations.js';
55
import {SoloError} from '../../errors.js';
66
import {BaseComponent} from './components/base_component.js';
77
import {RelayComponent} from './components/relay_component.js';
@@ -16,8 +16,10 @@ import {
1616
type IConsensusNodeComponent,
1717
type IRelayComponent,
1818
type ComponentName,
19+
type NamespaceNameAsString,
1920
} from './types.js';
2021
import {type ToObject, type Validate} from '../../../types/index.js';
22+
import * as cluster from 'node:cluster';
2123

2224
/**
2325
* Represent the components in the remote config and handles:
@@ -230,6 +232,32 @@ export class ComponentsDataWrapper implements Validate, ToObject<ComponentsDataS
230232
return new ComponentsDataWrapper();
231233
}
232234

235+
public static initializeWithNodes(
236+
nodeAliases: string[],
237+
cluster: string,
238+
namespace: NamespaceNameAsString,
239+
): ComponentsDataWrapper {
240+
const consensusNodeComponents: Record<ComponentName, ConsensusNodeComponent> = {};
241+
nodeAliases.forEach((alias, index) => {
242+
consensusNodeComponents[alias] = new ConsensusNodeComponent(
243+
alias,
244+
cluster,
245+
namespace,
246+
ConsensusNodeStates.INITIALIZED,
247+
index,
248+
);
249+
});
250+
const componentDataWrapper = new ComponentsDataWrapper(
251+
undefined,
252+
undefined,
253+
undefined,
254+
undefined,
255+
consensusNodeComponents,
256+
undefined,
257+
);
258+
return componentDataWrapper;
259+
}
260+
233261
/** checks if component exists in the respective group */
234262
private exists(components: Record<ComponentName, BaseComponent>, newComponent: BaseComponent): boolean {
235263
return Object.values(components).some(component => BaseComponent.compare(component, newComponent));

src/core/config/remote/remote_config_manager.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {NamespaceName} from '../../kube/resources/namespace/namespace_name.js';
2727
import {ResourceNotFoundError} from '../../kube/errors/resource_operation_errors.js';
2828
import {InjectTokens} from '../../dependency_injection/inject_tokens.js';
2929
import {Cluster} from './cluster.js';
30+
import {splitFlagInput} from '../../helpers.js';
3031

3132
/**
3233
* Uses Kubernetes ConfigMaps to manage the remote configuration data by creating, loading, modifying,
@@ -102,12 +103,19 @@ export class RemoteConfigManager {
102103
},
103104
);
104105

106+
// temporary workaround until we can have `solo deployment add` command
107+
const nodeAliases: string[] = splitFlagInput(this.configManager.getFlag(flags.nodeAliasesUnparsed));
108+
105109
this.remoteConfig = new RemoteConfigDataWrapper({
106110
metadata: new RemoteConfigMetadata(this.getNamespace().name, new Date(), this.localConfig.userEmailAddress),
107111
clusters,
108112
commandHistory: ['deployment create'],
109113
lastExecutedCommand: 'deployment create',
110-
components: ComponentsDataWrapper.initializeEmpty(),
114+
components: ComponentsDataWrapper.initializeWithNodes(
115+
nodeAliases,
116+
this.configManager.getFlag(flags.deploymentClusters),
117+
this.getNamespace().name,
118+
),
111119
flags: await CommonFlagsDataWrapper.initialize(this.configManager, argv),
112120
});
113121

@@ -133,12 +141,16 @@ export class RemoteConfigManager {
133141
private async load(): Promise<boolean> {
134142
if (this.remoteConfig) return true;
135143

136-
const configMap = await this.getConfigMap();
137-
if (!configMap) return false;
144+
try {
145+
const configMap = await this.getConfigMap();
138146

139-
this.remoteConfig = RemoteConfigDataWrapper.fromConfigmap(this.configManager, configMap);
147+
if (!configMap) return false;
148+
this.remoteConfig = RemoteConfigDataWrapper.fromConfigmap(this.configManager, configMap);
140149

141-
return true;
150+
return true;
151+
} catch {
152+
return false;
153+
}
142154
}
143155

144156
/**

src/core/kube/k8_client/resources/namespace/k8_client_namespaces.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
* SPDX-License-Identifier: Apache-2.0
33
*/
44
import {type Namespaces} from '../../../resources/namespace/namespaces.js';
5-
import {type CoreV1Api} from '@kubernetes/client-node';
5+
import {type V1Status, type CoreV1Api} from '@kubernetes/client-node';
66
import {StatusCodes} from 'http-status-codes';
77
import {SoloError} from '../../../../errors.js';
88
import {NamespaceName} from '../../../resources/namespace/namespace_name.js';
9+
import {ResourceDeleteError} from '../../../errors/resource_operation_errors.js';
10+
import {ResourceType} from '../../../resources/resource_type.js';
911

1012
export class K8ClientNamespaces implements Namespaces {
1113
constructor(private readonly kubeClient: CoreV1Api) {}
@@ -22,8 +24,12 @@ export class K8ClientNamespaces implements Namespaces {
2224
}
2325

2426
public async delete(namespace: NamespaceName): Promise<boolean> {
25-
const resp = await this.kubeClient.deleteNamespace(namespace.name);
26-
return resp.response.statusCode === StatusCodes.OK;
27+
try {
28+
const resp: {response: any; body?: V1Status} = await this.kubeClient.deleteNamespace(namespace.name);
29+
return resp.response.statusCode === StatusCodes.OK;
30+
} catch {
31+
return false;
32+
}
2733
}
2834

2935
public async has(namespace: NamespaceName): Promise<boolean> {

test/e2e/commands/network.test.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,17 @@ import {type NetworkNodes} from '../../../src/core/network_nodes.js';
2020
import {container} from 'tsyringe-neo';
2121
import {InjectTokens} from '../../../src/core/dependency_injection/inject_tokens.js';
2222

23-
describe('NetworkCommand', () => {
23+
describe('NetworkCommand', function networkCommand() {
24+
this.bail(true);
2425
const testName = 'network-cmd-e2e';
2526
const namespace = NamespaceName.of(testName);
2627
const applicationEnvFileContents = '# row 1\n# row 2\n# row 3';
2728
const applicationEnvParentDirectory = path.join(getTmpDir(), 'network-command-test');
2829
const applicationEnvFilePath = path.join(applicationEnvParentDirectory, 'application.env');
29-
const argv = getDefaultArgv();
30+
const argv = getDefaultArgv(namespace);
3031
// argv[flags.namespace.name] = namespace.name;
3132
argv[flags.releaseTag.name] = HEDERA_PLATFORM_VERSION_TAG;
32-
// argv[flags.nodeAliasesUnparsed.name] = 'node1';
33+
argv[flags.nodeAliasesUnparsed.name] = 'node1';
3334
argv[flags.generateGossipKeys.name] = true;
3435
argv[flags.generateTlsKeys.name] = true;
3536
argv[flags.deployMinio.name] = true;
@@ -49,6 +50,7 @@ describe('NetworkCommand', () => {
4950
const clusterCmd = bootstrapResp.cmd.clusterCmd;
5051
const initCmd = bootstrapResp.cmd.initCmd;
5152
const nodeCmd = bootstrapResp.cmd.nodeCmd;
53+
const deploymentCmd = bootstrapResp.cmd.deploymentCmd;
5254

5355
after(async function () {
5456
this.timeout(Duration.ofMinutes(3).toMillis());
@@ -59,13 +61,19 @@ describe('NetworkCommand', () => {
5961
});
6062

6163
before(async () => {
64+
await k8Factory.default().namespaces().delete(namespace);
6265
await initCmd.init(argv);
6366
await clusterCmd.handlers.setup(argv);
6467
fs.mkdirSync(applicationEnvParentDirectory, {recursive: true});
6568
fs.writeFileSync(applicationEnvFilePath, applicationEnvFileContents);
6669
});
6770

68-
it('deployment create should succeed', async () => {});
71+
it('deployment create should succeed', async () => {
72+
expect(await deploymentCmd.create(argv)).to.be.true;
73+
argv[flags.nodeAliasesUnparsed.name] = undefined;
74+
configManager.reset();
75+
configManager.update(argv);
76+
});
6977

7078
it('keys should be generated', async () => {
7179
expect(await nodeCmd.handlers.keys(argv)).to.be.true;

test/test_container.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ export function resetForTest(namespace?: NamespaceNameAsString, cacheDir: string
2727
parsedData.deployments['deployment'].namespace = namespace;
2828
}
2929

30-
fs.writeFileSync(path.join(cacheDirectory, localConfigFile), yaml.stringify(parsedData));
30+
// need to init the container prior to using K8Client for dependency injection to work
3131
resetTestContainer(cacheDir);
3232

3333
parsedData.clusterRefs['cluster-1'] = new K8Client(undefined).contexts().readCurrent();
34+
fs.writeFileSync(path.join(cacheDirectory, localConfigFile), yaml.stringify(parsedData));
3435
}

0 commit comments

Comments
 (0)