Skip to content

Commit

Permalink
feat: implement IOC in core classes
Browse files Browse the repository at this point in the history
Signed-off-by: Ivo Yankov <[email protected]>
  • Loading branch information
Ivo-Yankov committed Dec 19, 2024
1 parent c582f12 commit 507a081
Show file tree
Hide file tree
Showing 34 changed files with 195 additions and 219 deletions.
13 changes: 6 additions & 7 deletions src/core/account_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ import type {NetworkNodeServices} from './network_node_services.js';
import {NetworkNodeServicesBuilder} from './network_node_services.js';
import path from 'path';

import {type SoloLogger} from './logging.js';
import {type K8} from './k8.js';
import {SoloLogger} from './logging.js';
import {K8} from './k8.js';
import {type AccountIdWithKeyPairObject, type ExtendedNetServer} from '../types/index.js';
import {type NodeAlias, type PodName} from '../types/aliases.js';
import {IGNORED_NODE_ACCOUNT_ID} from './constants.js';
import {autoInjectable} from "tsyringe-neo";

const REASON_FAILED_TO_GET_KEYS = 'failed to get keys for accountId';
const REASON_SKIPPED = 'skipped since it does not have a genesis key';
Expand All @@ -55,17 +56,15 @@ const REASON_FAILED_TO_CREATE_K8S_S_KEY = 'failed to create k8s scrt key';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

@autoInjectable()
export class AccountManager {
private _portForwards: ExtendedNetServer[];
public _nodeClient: Client | null;

constructor(
private readonly logger: SoloLogger,
private readonly k8: K8,
private readonly logger?: SoloLogger,
private readonly k8?: K8,
) {
if (!logger) throw new Error('An instance of core/SoloLogger is required');
if (!k8) throw new Error('An instance of core/K8 is required');

this._portForwards = [];
this._nodeClient = null;
}
Expand Down
20 changes: 9 additions & 11 deletions src/core/certificate_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,23 @@ import fs from 'fs';
import {Templates} from './templates.js';
import {GrpcProxyTlsEnums} from './enumerations.js';

import type {ConfigManager} from './config_manager.js';
import type {K8} from './k8.js';
import type {SoloLogger} from './logging.js';
import {ConfigManager} from './config_manager.js';
import {K8} from './k8.js';
import {SoloLogger} from './logging.js';
import type {ListrTaskWrapper} from 'listr2';
import type {NodeAlias} from '../types/aliases.js';
import {autoInjectable} from "tsyringe-neo";

/**
* Used to handle interactions with certificates data and inject it into the K8s cluster secrets
*/
@autoInjectable()
export class CertificateManager {
constructor(
private readonly k8: K8,
private readonly logger: SoloLogger,
private readonly configManager: ConfigManager,
) {
if (!k8) throw new MissingArgumentError('an instance of core/K8 is required');
if (!logger) throw new MissingArgumentError('an instance of core/SoloLogger is required');
if (!configManager) throw new MissingArgumentError('an instance of core/ConfigManager is required');
}
private readonly k8?: K8,
private readonly logger?: SoloLogger,
private readonly configManager?: ConfigManager,
) {}

/**
* Reads the certificate and key and build the secret with the appropriate structure
Expand Down
15 changes: 7 additions & 8 deletions src/core/chart_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,18 @@
*
*/
import * as constants from './constants.js';
import {type Helm} from './helm.js';
import {Helm} from './helm.js';
import chalk from 'chalk';
import {SoloError} from './errors.js';
import {type SoloLogger} from './logging.js';
import {SoloLogger} from './logging.js';
import {autoInjectable} from "tsyringe-neo";

@autoInjectable()
export class ChartManager {
constructor(
private readonly helm: Helm,
private readonly logger: SoloLogger,
) {
if (!logger) throw new Error('An instance of core/SoloLogger is required');
if (!helm) throw new Error('An instance of core/Helm is required');
}
private readonly helm?: Helm,
private readonly logger?: SoloLogger,
) {}

/**
* Setup chart repositories
Expand Down
11 changes: 6 additions & 5 deletions src/core/config/local_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ import * as yaml from 'yaml';
import {Flags as flags} from '../../commands/flags.js';
import {type Deployments, type DeploymentStructure, type LocalConfigData} from './local_config_data.js';
import {MissingArgumentError, SoloError} from '../errors.js';
import {type SoloLogger} from '../logging.js';
import {SoloLogger} from '../logging.js';
import {IsDeployments} from '../validator_decorators.js';
import type {ConfigManager} from '../config_manager.js';
import {ConfigManager} from '../config_manager.js';
import type {EmailAddress, Namespace} from './remote/types.js';
import {Templates} from '../templates.js';
import {ErrorMessages} from '../error_messages.js';
import {autoInjectable} from "tsyringe-neo";

@autoInjectable()
export class LocalConfig implements LocalConfigData {
@IsEmail(
{},
Expand Down Expand Up @@ -58,11 +60,10 @@ export class LocalConfig implements LocalConfigData {

public constructor(
private readonly filePath: string,
private readonly logger: SoloLogger,
private readonly configManager: ConfigManager,
private readonly logger?: SoloLogger,
private readonly configManager?: ConfigManager,
) {
if (!filePath || filePath === '') throw new MissingArgumentError('a valid filePath is required');
if (!logger) throw new Error('An instance of core/SoloLogger is required');

const allowedKeys = ['userEmailAddress', 'deployments', 'currentDeploymentName'];
if (this.configFileExists()) {
Expand Down
18 changes: 10 additions & 8 deletions src/core/config/remote/remote_config_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@ import {Flags as flags} from '../../../commands/flags.js';
import * as yaml from 'yaml';
import {ComponentsDataWrapper} from './components_data_wrapper.js';
import {RemoteConfigValidator} from './remote_config_validator.js';
import type {K8} from '../../k8.js';
import {K8} from '../../k8.js';
import type {Cluster, Namespace} from './types.js';
import type {SoloLogger} from '../../logging.js';
import type {ConfigManager} from '../../config_manager.js';
import type {LocalConfig} from '../local_config.js';
import {SoloLogger} from '../../logging.js';
import {ConfigManager} from '../../config_manager.js';
import {LocalConfig} from '../local_config.js';
import type {DeploymentStructure} from '../local_config_data.js';
import {type ContextClusterStructure} from '../../../types/config_types.js';
import {type EmptyContextConfig, type Optional, type SoloListrTask} from '../../../types/index.js';
import type * as k8s from '@kubernetes/client-node';
import {StatusCodes} from 'http-status-codes';
import {autoInjectable} from "tsyringe-neo";

interface ListrContext {
config: {contextCluster: ContextClusterStructure};
Expand All @@ -42,6 +43,7 @@ interface ListrContext {
* Uses Kubernetes ConfigMaps to manage the remote configuration data by creating, loading, modifying,
* and saving the configuration data to and from a Kubernetes cluster.
*/
@autoInjectable()
export class RemoteConfigManager {
/** Stores the loaded remote configuration data. */
private remoteConfig: Optional<RemoteConfigDataWrapper>;
Expand All @@ -53,10 +55,10 @@ export class RemoteConfigManager {
* @param configManager - Manager to retrieve application flags and settings.
*/
public constructor(
private readonly k8: K8,
private readonly logger: SoloLogger,
private readonly localConfig: LocalConfig,
private readonly configManager: ConfigManager,
private readonly k8?: K8,
private readonly logger?: SoloLogger,
private readonly localConfig?: LocalConfig,
private readonly configManager?: ConfigManager,
) {}

/* ---------- Getters ---------- */
Expand Down
9 changes: 4 additions & 5 deletions src/core/config_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* limitations under the Licen}se.
*
*/
import {SoloError, MissingArgumentError, IllegalArgumentError} from './errors.js';
Expand All @@ -22,20 +22,19 @@ import * as helpers from './helpers.js';
import type * as yargs from 'yargs';
import {type CommandFlag} from '../types/flag_types.js';
import {type ListrTaskWrapper} from 'listr2';
import {autoInjectable} from "tsyringe-neo";

/**
* ConfigManager cache command flag values so that user doesn't need to enter the same values repeatedly.
*
* For example, 'namespace' is usually remains the same across commands once it is entered, and therefore user
* doesn't need to enter it repeatedly. However, user should still be able to specify the flag explicitly for any command.
*/
@autoInjectable()
export class ConfigManager {
config!: Record<string, any>;

constructor(private readonly logger: SoloLogger) {
if (!logger || !(logger instanceof SoloLogger))
throw new MissingArgumentError('An instance of core/SoloLogger is required');

constructor(private readonly logger?: SoloLogger) {
this.reset();
}

Expand Down
26 changes: 13 additions & 13 deletions src/core/container_init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@ container.register<Zippy>(Zippy, {useValue: new Zippy()});
container.register<HelmDependencyManager>(HelmDependencyManager, {useValue: new HelmDependencyManager()});
container.register<DependencyManager>(DependencyManager, {useValue: new DependencyManager()});
container.register<Helm>(Helm, {useValue: new Helm()});
container.register<ChartManager>(ChartManager, {useValue: new ChartManager()});
container.register<ConfigManager>(ConfigManager, {useValue: new ConfigManager()});
container.register<K8>(K8, {useValue: new K8()});
container.register<AccountManager>(AccountManager, {useValue: new AccountManager()});
container.register<PlatformInstaller>(PlatformInstaller, {useValue: new PlatformInstaller()});
container.register<KeyManager>(KeyManager, {useValue: new KeyManager()});
container.register<ProfileManager>(ProfileManager, {useValue: new ProfileManager()});
container.register<IntervalLeaseRenewalService>(IntervalLeaseRenewalService, {useValue: new IntervalLeaseRenewalService()});
container.register<LeaseManager>(LeaseManager, {useValue: new LeaseManager(container.resolve(IntervalLeaseRenewalService))});
container.register<CertificateManager>(CertificateManager, {useValue: new CertificateManager()});

const localConfigPath = path.join(constants.SOLO_CACHE_DIR, constants.DEFAULT_LOCAL_CONFIG_FILE);
container.register<LocalConfig>(LocalConfig, {useValue: new LocalConfig(localConfigPath)});

// const chartManager = new ChartManager(helm, logger);
// const configManager = new ConfigManager(logger);
// const k8 = new K8(configManager, logger);
// const accountManager = new AccountManager(logger, k8);
// const platformInstaller = new PlatformInstaller(logger, k8, configManager);
// const keyManager = new KeyManager(logger);
// const profileManager = new ProfileManager(logger, configManager);
// const leaseRenewalService: LeaseRenewalService = new IntervalLeaseRenewalService();
// const leaseManager = new LeaseManager(k8, configManager, logger, leaseRenewalService);
// const certificateManager = new CertificateManager(k8, logger, configManager);
// const localConfigPath = path.join(constants.SOLO_CACHE_DIR, constants.DEFAULT_LOCAL_CONFIG_FILE);
// const localConfig = new LocalConfig(localConfigPath, logger, configManager);
// const remoteConfigManager = new RemoteConfigManager(k8, logger, localConfig, configManager);
const remoteConfigManager = container.resolve(RemoteConfigManager);
15 changes: 7 additions & 8 deletions src/core/k8.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ import {getReasonPhrase, StatusCodes} from 'http-status-codes';

import {sleep} from './helpers.js';
import * as constants from './constants.js';
import {type ConfigManager} from './config_manager.js';
import {type SoloLogger} from './logging.js';
import {ConfigManager} from './config_manager.js';
import {SoloLogger} from './logging.js';
import {type PodName, type TarCreateFilter} from '../types/aliases.js';
import type {ExtendedNetServer, LocalContextObject} from '../types/index.js';
import {HEDERA_HAPI_PATH, ROOT_CONTAINER, SOLO_LOGS_DIR} from './constants.js';
import {Duration} from './time/duration.js';
import {autoInjectable, container} from "tsyringe-neo";

interface TDirectoryData {
directory: boolean;
Expand All @@ -53,6 +54,7 @@ interface TDirectoryData {
* 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()
*/
@autoInjectable()
export class K8 {
private _cachedContexts: Context[];

Expand All @@ -65,12 +67,9 @@ export class K8 {
private coordinationApiClient: k8s.CoordinationV1Api;

constructor(
private readonly configManager: ConfigManager,
public readonly logger: SoloLogger,
private readonly configManager?: ConfigManager,
public readonly logger?: SoloLogger,
) {
if (!configManager) throw new MissingArgumentError('An instance of core/ConfigManager is required');
if (!logger) throw new MissingArgumentError('An instance of core/SoloLogger is required');

this.init();
}

Expand All @@ -79,7 +78,7 @@ export class K8 {
* Internally it instantiates a new kube API client
*/
clone() {
const c = new K8(this.configManager, this.logger);
const c = container.resolve(K8);
return c.init();
}

Expand Down
8 changes: 3 additions & 5 deletions src/core/key_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ import chalk from 'chalk';
import {type NodeAlias, type NodeAliases} from '../types/aliases.js';
import {type NodeKeyObject, type PrivateKeyAndCertificateObject} from '../types/index.js';
import type {ListrTask} from 'listr2';
import {autoInjectable} from "tsyringe-neo";

// @ts-ignore
x509.cryptoProvider.set(crypto);

@autoInjectable()
export class KeyManager {
static SigningKeyAlgo = {
name: 'RSASSA-PKCS1-v1_5',
Expand Down Expand Up @@ -60,11 +62,7 @@ export class KeyManager {
hash: 'SHA-384',
};

constructor(private readonly logger: SoloLogger) {
if (!logger || !(logger instanceof SoloLogger))
throw new MissingArgumentError('An instance of core/SoloLogger is required');
this.logger = logger;
}
constructor(private readonly logger?: SoloLogger) {}

/** Convert CryptoKey into PEM string */
async convertPrivateKeyToPem(privateKey: CryptoKey) {
Expand Down
2 changes: 2 additions & 0 deletions src/core/lease/interval_lease_renewal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
*/
import {type Lease, type LeaseRenewalService} from './lease.js';
import {Duration} from '../time/duration.js';
import {autoInjectable} from "tsyringe-neo";

/**
* Implements a lease renewal service which utilizes a setInterval() based approach to renew leases at regular intervals.
* The renewal delay is calculated as half the duration of the lease in seconds.
*/
@autoInjectable()
export class IntervalLeaseRenewalService implements LeaseRenewalService {
/** The internal registry used to track all non-cancelled lease renewals. */
private readonly _scheduledLeases: Map<number, Lease>;
Expand Down
35 changes: 11 additions & 24 deletions src/core/lease/lease_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,21 @@
* limitations under the License.
*
*/
import {MissingArgumentError} from '../errors.js';
import {Flags as flags} from '../../commands/flags.js';
import type {ConfigManager} from '../config_manager.js';
import type {K8} from '../k8.js';
import type {SoloLogger} from '../logging.js';
import {type Lease, type LeaseRenewalService} from './lease.js';
import {ConfigManager} from '../config_manager.js';
import {K8} from '../k8.js';
import {SoloLogger} from '../logging.js';
import {type Lease, LeaseRenewalService} from './lease.js';
import {IntervalLease} from './interval_lease.js';
import {LeaseHolder} from './lease_holder.js';
import {LeaseAcquisitionError} from './lease_errors.js';
import {autoInjectable} from "tsyringe-neo";

/**
* Manages the acquisition and renewal of leases.
*/
@autoInjectable()
export class LeaseManager {
/** The injected logger instance. */
private readonly _logger: SoloLogger;

/** The injected lease renewal service instance. */
private readonly _renewalService: LeaseRenewalService;

/**
* Creates a new lease manager.
*
Expand All @@ -43,19 +38,11 @@ export class LeaseManager {
* @param renewalService - the lease renewal service.
*/
constructor(
private readonly k8: K8,
private readonly configManager: ConfigManager,
logger: SoloLogger,
renewalService: LeaseRenewalService,
) {
if (!k8) throw new MissingArgumentError('an instance of core/K8 is required');
if (!logger) throw new MissingArgumentError('an instance of core/SoloLogger is required');
if (!configManager) throw new MissingArgumentError('an instance of core/ConfigManager is required');
if (!renewalService) throw new MissingArgumentError('an instance of core/LeaseRenewalService is required');

this._logger = logger;
this._renewalService = renewalService;
}
private readonly _renewalService?: LeaseRenewalService,
private readonly _logger?: SoloLogger,
private readonly k8?: K8,
private readonly configManager?: ConfigManager
) {}

/**
* Creates a new lease. This lease is not acquired until the `acquire` method is called.
Expand Down
Loading

0 comments on commit 507a081

Please sign in to comment.