UNPKG

@hashgraph/solo

Version:

An opinionated CLI tool to deploy and manage private Hedera Networks.

114 lines 4.75 kB
// 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