@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
114 lines • 4.75 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import { ipV4ToBase64, isIpV4Address } from '../../core/helpers.js';
import { SoloError } from '../../core/errors/solo-error.js';
import { NamespaceName } from '../../types/namespace/namespace-name.js';
import { Templates } from '../../core/templates.js';
export class Address {
port;
fqdnOrIpAddress;
ipAddressV4;
domainName;
ipAddressV4Base64;
constructor(port, fqdnOrIpAddress, ipAddressV4, domainName, ipAddressV4Base64) {
this.port = port;
this.fqdnOrIpAddress = fqdnOrIpAddress;
this.ipAddressV4 = ipAddressV4;
this.domainName = domainName;
this.ipAddressV4Base64 = ipAddressV4Base64;
this.port = port;
this.fqdnOrIpAddress = fqdnOrIpAddress;
if (this.fqdnOrIpAddress) {
if (isIpV4Address(fqdnOrIpAddress)) {
this.ipAddressV4 = fqdnOrIpAddress;
this.ipAddressV4Base64 = ipV4ToBase64(fqdnOrIpAddress);
return;
}
else {
this.domainName = fqdnOrIpAddress;
return;
}
}
if (this.domainName) {
this.domainName = domainName;
return;
}
this.ipAddressV4 = ipAddressV4;
this.ipAddressV4Base64 = ipAddressV4Base64;
if (this.ipAddressV4 && !this.ipAddressV4Base64) {
this.ipAddressV4Base64 = ipV4ToBase64(this.ipAddressV4);
}
if (this.ipAddressV4Base64 && !this.ipAddressV4) {
// TODO: implement base64 to IPv4 conversion if needed
throw new Error('ipAddressV4 must be provided if ipAddressV4Base64 is set');
}
if (!this.ipAddressV4 && !this.ipAddressV4Base64) {
throw new Error('Either domainName or ipAddressV4 must be provided');
}
}
formattedAddress() {
if (this.domainName) {
return `${this.domainName}:${this.port}`;
}
else if (this.ipAddressV4) {
return `${this.ipAddressV4}:${this.port}`;
}
else {
throw new Error('Address is not properly initialized');
}
}
hostString() {
if (this.domainName) {
return this.domainName;
}
else if (this.ipAddressV4) {
return this.ipAddressV4;
}
else {
throw new Error('Address is not properly initialized');
}
}
static async getExternalAddress(consensusNode, k8, port, gossipFqdnRestricted = true) {
return Address.resolveLoadBalancerAddress(consensusNode, k8, port, gossipFqdnRestricted);
}
static async resolveLoadBalancerAddress(consensusNode, k8, port, gossipFqdnRestricted) {
const namespace = NamespaceName.of(consensusNode.namespace);
try {
const serviceList = await k8
.services()
.list(namespace, Templates.renderNodeSvcLabelsFromNodeId(consensusNode.nodeId));
if (serviceList && serviceList.length > 0) {
const svc = serviceList[0];
if (!svc.metadata.name.startsWith('network-node')) {
throw new SoloError(`Service found is not a network node service: ${svc.metadata.name}`);
}
if (svc.spec.type === 'LoadBalancer' &&
svc.status?.loadBalancer?.ingress &&
svc.status.loadBalancer.ingress.length > 0) {
for (let index = 0; index < svc.status.loadBalancer.ingress.length; index++) {
const ingress = svc.status.loadBalancer.ingress[index];
if (ingress.hostname) {
return new Address(port, ingress.hostname);
}
else if (ingress.ip) {
return new Address(port, ingress.ip);
}
}
}
// If gossip FQDN is allowed by node config, keep using the service FQDN fallback.
if (!gossipFqdnRestricted) {
return new Address(port, consensusNode.fullyQualifiedDomainName);
}
// When gossip FQDN is restricted and no LoadBalancer IP is available
// (e.g., Kind/NodePort), use cluster IP to avoid CN validation failure.
if (svc.spec?.clusterIP && svc.spec.clusterIP !== 'None') {
return new Address(port, svc.spec.clusterIP);
}
}
}
catch {
// Ignore and use FQDN
}
return new Address(port, consensusNode.fullyQualifiedDomainName);
}
}
//# sourceMappingURL=address.js.map