Skip to content

Commit

Permalink
feat(fabric): serialization of ccp and sshconfig
Browse files Browse the repository at this point in the history
    Primary Changes
    ---------------
    1. sshConfig and connectionProfile can now be passed
       as base64 encoded strings

    Changes required to incorporate 1)
    ---------------------------------
    2. Added sshConfigBase64Encoded and
       connectionProfileBase64encoded properties
       to IPluginLedgerConnectorFabricOptions
    3. Added necessary FabricConnector class variables
    4. Added a new testcase to demonstrate
       the same
    5. Updated an implementation which fetches
       sshConfig from class variable

Fixes #3577

Signed-off-by: jagpreetsinghsasan <[email protected]>
  • Loading branch information
jagpreetsinghsasan committed Dec 2, 2024
1 parent 1c49527 commit 3c61af7
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import temp from "temp";
import fs from "fs/promises";

import {
Config as SshConfig,
NodeSSH,
SSHExecCommandOptions,
SSHExecCommandResponse,
Expand Down Expand Up @@ -35,6 +36,7 @@ export interface IDeployContractGoSourceImplFabricV256Context {
readonly log: Logger;
readonly className: string;
readonly dockerBinary: string;
readonly sshConfig: SshConfig;
readonly opts: IPluginLedgerConnectorFabricOptions;
}

Expand All @@ -53,7 +55,7 @@ export async function deployContractGoSourceImplFabricV256(
ctx.opts.cliContainerGoPath || K_DEFAULT_CLI_CONTAINER_GO_PATH;

const ssh = new NodeSSH();
await ssh.connect(ctx.opts.sshConfig);
await ssh.connect(ctx.sshConfig);
log.debug(`SSH connection OK`);

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,11 @@ export interface IPluginLedgerConnectorFabricOptions
cliContainerGoPath?: string;
cliContainerEnv: NodeJS.ProcessEnv;
pluginRegistry: PluginRegistry;
sshConfig: SshConfig;
sshConfig?: SshConfig;
sshConfigB64?: string;
readonly sshDebugOn?: boolean;
connectionProfile: ConnectionProfile;
connectionProfile?: ConnectionProfile;
connectionProfileB64?: string;
prometheusExporter?: PrometheusExporter;
discoveryOptions?: GatewayDiscoveryOptions;
eventHandlerOptions?: GatewayEventHandlerOptions;
Expand Down Expand Up @@ -219,6 +221,8 @@ export class PluginLedgerConnectorFabric
private readonly peerBinary: string;
private readonly goBinary: string;
private readonly cliContainerGoPath: string;
private readonly sshConfig: SshConfig;
private readonly connectionProfile: ConnectionProfile;
public prometheusExporter: PrometheusExporter;
private endpoints: IWebServiceEndpoint[] | undefined;
private readonly secureIdentity: SecureIdentityProviders;
Expand All @@ -241,7 +245,6 @@ export class PluginLedgerConnectorFabric
Checks.truthy(opts.instanceId, `${fnTag} options.instanceId`);
Checks.truthy(opts.peerBinary, `${fnTag} options.peerBinary`);
Checks.truthy(opts.pluginRegistry, `${fnTag} options.pluginRegistry`);
Checks.truthy(opts.connectionProfile, `${fnTag} options.connectionProfile`);
this.prometheusExporter =
opts.prometheusExporter ||
new PrometheusExporter({ pollingIntervalInMin: 1 });
Expand Down Expand Up @@ -277,9 +280,33 @@ export class PluginLedgerConnectorFabric
});
this.certStore = new CertDatastore(opts.pluginRegistry);

if (this.opts.connectionProfile) {
this.connectionProfile = this.opts.connectionProfile;
} else if (this.opts.connectionProfileB64) {
const connectionProfileBuffer = Buffer.from(
this.opts.connectionProfileB64,
"base64",
);
const connectionProfileString = connectionProfileBuffer.toString("utf-8");
this.connectionProfile = JSON.parse(connectionProfileString);
} else {
throw new Error(
"Cannot instantiate Fabric connector without connection profile.",
);
}

this.sshDebugOn = opts.sshDebugOn === true;
if (this.opts.sshConfig) {
this.sshConfig = this.opts.sshConfig;
} else if (this.opts.sshConfigB64) {
const sshConfigBuffer = Buffer.from(this.opts.sshConfigB64, "base64");
const sshConfigString = sshConfigBuffer.toString("utf-8");
this.sshConfig = JSON.parse(sshConfigString);
} else {
throw new Error("Cannot instantiate Fabric connector without SSH config");
}
if (this.sshDebugOn) {
this.opts.sshConfig = this.enableSshDebugLogs(this.opts.sshConfig);
this.sshConfig = this.enableSshDebugLogs(this.sshConfig);
}

this.signCallback = opts.signCallback;
Expand Down Expand Up @@ -361,11 +388,11 @@ export class PluginLedgerConnectorFabric
req: DeployContractV1Request,
): Promise<DeployContractV1Response> {
const fnTag = `${this.className}#deployContract()`;
const { log, opts } = this;
const { log } = this;

const ssh = new NodeSSH();
this.log.debug(`${fnTag} Establishing SSH connection to peer...`);
await ssh.connect(opts.sshConfig);
await ssh.connect(this.sshConfig);
this.log.debug(`${fnTag} Established SSH connection to peer OK.`);

if (req.collectionsConfigFile) {
Expand Down Expand Up @@ -666,6 +693,7 @@ export class PluginLedgerConnectorFabric
log,
opts: this.opts,
dockerBinary: this.dockerBinary,
sshConfig: this.sshConfig,
className: this.className,
};
return deployContractGoSourceImplFabricV256(ctx, req);
Expand Down Expand Up @@ -910,7 +938,7 @@ export class PluginLedgerConnectorFabric
return createGateway({
logLevel: this.opts.logLevel,
pluginRegistry: this.opts.pluginRegistry,
defaultConnectionProfile: this.opts.connectionProfile,
defaultConnectionProfile: this.connectionProfile,
defaultDiscoveryOptions: this.opts.discoveryOptions || {
enabled: true,
asLocalhost: true,
Expand All @@ -935,7 +963,8 @@ export class PluginLedgerConnectorFabric
protected async createGatewayLegacy(
signingCredential: FabricSigningCredential,
): Promise<Gateway> {
const { connectionProfile, eventHandlerOptions: eho } = this.opts;
const { eventHandlerOptions: eho } = this.opts;
const connectionProfile = this.connectionProfile;

const iType = signingCredential.type || FabricSigningCredentialType.X509;

Expand Down Expand Up @@ -1264,7 +1293,7 @@ export class PluginLedgerConnectorFabric
public async createCaClient(caId: string): Promise<FabricCAServices> {
const fnTag = `${this.className}#createCaClient()`;
try {
const ccp = this.opts.connectionProfile;
const ccp = this.connectionProfile;
if (!ccp.certificateAuthorities) {
throw new Error(`${fnTag} conn. profile certificateAuthorities falsy.`);
}
Expand Down Expand Up @@ -1669,7 +1698,7 @@ export class PluginLedgerConnectorFabric
this.log.debug("Create Fabric Client without a signer with ID", clientId);
const client = new Client(clientId);
// Use fabric SDK methods for parsing connection profile into Client structure
await loadFromConfig(client, this.opts.connectionProfile);
await loadFromConfig(client, this.connectionProfile);

// Create user
const user = User.createUser("", "", signerMspID, signerCertificate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,32 @@ describe(testCase, () => {
}

{
const connectionProfileString = JSON.stringify(connectionProfile);
const connectionProfileB64Buffer = Buffer.from(connectionProfileString);
const sshConfigString = JSON.stringify(sshConfig);
const connectionProfileB64 =
connectionProfileB64Buffer.toString("base64");
const sshConfigB64Buffer = Buffer.from(sshConfigString);
const sshConfigB64 = sshConfigB64Buffer.toString("base64");
const pluginOptionsSerialized: IPluginLedgerConnectorFabricOptions = {
instanceId: uuidv4(),
pluginRegistry,
sshConfigB64,
cliContainerEnv: {},
peerBinary: "/fabric-samples/bin/peer",
logLevel,
connectionProfileB64,
discoveryOptions,
eventHandlerOptions: {
strategy: DefaultEventHandlerStrategy.NetworkScopeAllfortx,
commitTimeout: 300,
},
};
const pluginWithSerializedInputs = new PluginLedgerConnectorFabric(
pluginOptionsSerialized,
);
await pluginWithSerializedInputs.getOrCreateWebServices();
await pluginWithSerializedInputs.registerWebServices(expressApp);
const req: RunTransactionRequest = {
signingCredential,
gatewayOptions: {
Expand Down

0 comments on commit 3c61af7

Please sign in to comment.