UNPKG

@starship-ci/generator

Version:

Kubernetes manifest generator for Starship deployments

387 lines (386 loc) 11.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getChainId = exports.getHostname = exports.generateChainVolumes = exports.generateChainVolumeMounts = exports.extractImageTag = exports.generateImagePullSecrets = exports.generateWaitInitContainer = exports.getChainExposerAddrs = exports.getChainRestAddrs = exports.getChainGrpcAddrs = exports.getChainRpcAddrs = exports.getChainInternalRpcAddrs = exports.getChainNames = exports.getChainIds = exports.getPortMap = exports.getNodeResources = exports.getResourceObject = exports.getGenesisEnvVars = exports.getTimeoutEnvVars = exports.getChainEnvVars = exports.getDefaultEnvVars = exports.getSelectorLabels = exports.getCommonLabels = exports.getReleaseName = exports.getChainName = void 0; const version_1 = require("./version"); /** * Convert chain.id to name usable by templates * Replaces underscores with hyphens and truncates to 63 chars */ function getChainName(chainId) { return String(chainId).replace(/_/g, '-').substring(0, 63); } exports.getChainName = getChainName; /** * Create a default fully qualified app name */ function getReleaseName(config) { // Use the name from StarshipConfig const releaseName = config.name || 'starship'; return releaseName.substring(0, 63).replace(/-$/, ''); } exports.getReleaseName = getReleaseName; /** * Common labels for all resources */ function getCommonLabels(config) { return { ...getSelectorLabels(config), 'app.kubernetes.io/version': (0, version_1.getGeneratorVersion)(), 'app.kubernetes.io/managed-by': 'starship' }; } exports.getCommonLabels = getCommonLabels; /** * Selector labels for resources */ function getSelectorLabels(config) { return { 'starship.io/name': config.name }; } exports.getSelectorLabels = getSelectorLabels; /** * Default environment variables for chain containers */ function getDefaultEnvVars(chain) { return [ { name: 'DENOM', value: chain.denom || '' }, { name: 'COINS', value: chain.coins || '' }, { name: 'CHAIN_BIN', value: chain.binary || '' }, { name: 'CHAIN_DIR', value: chain.home || '' }, { name: 'CODE_REPO', value: chain.repo || '' }, { name: 'DAEMON_HOME', value: chain.home || '' }, { name: 'DAEMON_NAME', value: chain.binary || '' } ]; } exports.getDefaultEnvVars = getDefaultEnvVars; /** * Chain-specific environment variables */ function getChainEnvVars(chain) { return [{ name: 'CHAIN_ID', value: String(chain.id) }]; } exports.getChainEnvVars = getChainEnvVars; /** * Timeout environment variables */ function getTimeoutEnvVars(timeouts) { const envVars = []; for (const [key, value] of Object.entries(timeouts)) { envVars.push({ name: key.toUpperCase(), value: String(value) }); } return envVars; } exports.getTimeoutEnvVars = getTimeoutEnvVars; /** * Genesis-specific environment variables */ function getGenesisEnvVars(chain, port) { return [ { name: 'GENESIS_HOST', value: `${getChainName(String(chain.id))}-genesis` }, { name: 'GENESIS_PORT', value: String(port) }, { name: 'NAMESPACE', valueFrom: { fieldRef: { fieldPath: 'metadata.namespace' } } } ]; } exports.getGenesisEnvVars = getGenesisEnvVars; /** * Get resource object based on input * Handles both simple cpu/memory format and full k8s resource format */ function getResourceObject(resources) { if (!resources) { return {}; } if (resources.cpu && resources.memory) { // Simple format: { cpu: "0.5", memory: "500M" } return { limits: { cpu: resources.cpu, memory: resources.memory }, requests: { cpu: resources.cpu, memory: resources.memory } }; } // Full k8s format return resources; } exports.getResourceObject = getResourceObject; /** * Get node resources with chain-specific overrides */ function getNodeResources(chain, context) { if (chain.resources) { return getResourceObject(chain.resources); } return getResourceObject(context.resources?.node || { cpu: '0.5', memory: '500M' }); } exports.getNodeResources = getNodeResources; /** * Standard port mappings for Cosmos chains */ function getPortMap() { return { p2p: 26656, address: 26658, grpc: 9090, 'grpc-web': 9091, rest: 1317, rpc: 26657, metrics: 26660, exposer: 8081, faucet: 8000 }; } exports.getPortMap = getPortMap; /** * Returns comma-separated list of chain IDs */ function getChainIds(chains) { return chains.map((chain) => chain.id).join(','); } exports.getChainIds = getChainIds; /** * Returns comma-separated list of chain names * If chain name is custom, use chain id instead */ function getChainNames(chains) { return chains .map((chain) => (chain.name === 'custom' ? chain.id : chain.name)) .join(','); } exports.getChainNames = getChainNames; /** * Returns comma-separated list of internal RPC addresses */ function getChainInternalRpcAddrs(chains) { return chains .map((chain) => `http://${getChainName(String(chain.id))}-genesis.$(NAMESPACE).svc.cluster.local:26657`) .join(','); } exports.getChainInternalRpcAddrs = getChainInternalRpcAddrs; /** * Returns comma-separated list of RPC addresses */ function getChainRpcAddrs(chains, config) { const localhost = config.registry?.localhost; const ingress = config.ingress; return chains .map((chain) => { if (localhost && chain.ports?.rpc) { return `http://localhost:${chain.ports.rpc}`; } else if (ingress?.enabled && ingress.host) { const host = ingress.host.replace('*.', ''); return `https://rpc.${chain.id}-genesis.${host}`; } else { return `http://${getChainName(String(chain.id))}-genesis.$(NAMESPACE).svc.cluster.local:26657`; } }) .join(','); } exports.getChainRpcAddrs = getChainRpcAddrs; /** * Returns comma-separated list of GRPC addresses */ function getChainGrpcAddrs(chains, config) { const localhost = config.registry?.localhost; const ingress = config.ingress; return chains .map((chain) => { if (localhost && chain.ports?.grpc) { return `http://localhost:${chain.ports.grpc}`; } else if (ingress?.enabled && ingress.host) { const host = ingress.host.replace('*.', ''); return `https://grpc.${chain.id}-genesis.${host}`; } else { return `http://${getChainName(String(chain.id))}-genesis.$(NAMESPACE).svc.cluster.local:9091`; } }) .join(','); } exports.getChainGrpcAddrs = getChainGrpcAddrs; /** * Returns comma-separated list of REST addresses */ function getChainRestAddrs(chains, config) { const localhost = config.registry?.localhost; const ingress = config.ingress; return chains .map((chain) => { if (localhost && chain.ports?.rest) { return `http://localhost:${chain.ports.rest}`; } else if (ingress?.enabled && ingress.host) { const host = ingress.host.replace('*.', ''); return `https://rest.${chain.id}-genesis.${host}`; } else { return `http://${getChainName(String(chain.id))}-genesis.$(NAMESPACE).svc.cluster.local:1317`; } }) .join(','); } exports.getChainRestAddrs = getChainRestAddrs; /** * Returns comma-separated list of exposer addresses */ function getChainExposerAddrs(chains, port = 8081) { return chains .map((chain) => `http://${getChainName(String(chain.id))}-genesis.$(NAMESPACE).svc.cluster.local:${port}`) .join(','); } exports.getChainExposerAddrs = getChainExposerAddrs; /** * Generate init container for waiting on chains to be ready */ function generateWaitInitContainer(chainIDs, port, config) { const waitScript = chainIDs .map((chainID) => ` while [ $(curl -sw '%{http_code}' http://${getChainName(String(chainID))}-genesis.$NAMESPACE.svc.cluster.local:$GENESIS_PORT/node_id -o /dev/null) -ne 200 ]; do echo "Genesis validator does not seem to be ready for: ${chainID}. Waiting for it to start..." echo "Checking: http://${getChainName(String(chainID))}-genesis.$NAMESPACE.svc.cluster.local:$GENESIS_PORT/node_id" sleep 10; done`) .join('\n'); return { name: 'wait-for-chains', image: 'curlimages/curl:latest', imagePullPolicy: config?.images?.imagePullPolicy || 'IfNotPresent', env: [ { name: 'GENESIS_PORT', value: String(port) }, { name: 'NAMESPACE', valueFrom: { fieldRef: { fieldPath: 'metadata.namespace' } } } ], command: ['/bin/sh', '-c', `${waitScript}\necho "Ready to start"\nexit 0`], resources: getResourceObject(config?.resources?.wait || { cpu: '0.1', memory: '128M' }) }; } exports.generateWaitInitContainer = generateWaitInitContainer; /** * Generate image pull secrets */ function generateImagePullSecrets(imagePullSecrets) { if (!imagePullSecrets || imagePullSecrets.length === 0) { return null; } return { imagePullSecrets: imagePullSecrets.map((secret) => ({ name: secret.name })) }; } exports.generateImagePullSecrets = generateImagePullSecrets; /** * Extract tag from docker image */ function extractImageTag(image) { const match = image.match(/[^:]+$/); return match ? match[0] : 'latest'; } exports.extractImageTag = extractImageTag; /** * Generate volume mounts for chain containers */ function generateChainVolumeMounts(chain) { return [ { mountPath: chain.home, name: 'node' }, { mountPath: '/configs', name: 'addresses' }, { mountPath: '/scripts', name: 'scripts' } ]; } exports.generateChainVolumeMounts = generateChainVolumeMounts; /** * Generate standard volumes for chain pods */ function generateChainVolumes(chain) { const volumes = [ { name: 'node', emptyDir: {} }, { name: 'addresses', configMap: { name: 'keys' } }, { name: 'scripts', configMap: { name: `setup-scripts-${getChainName(String(chain.id))}` } } ]; // Add patch volume if genesis override exists if (chain.genesis) { volumes.push({ name: 'patch', configMap: { name: `patch-${getChainName(String(chain.id))}` } }); } // Add faucet volume if starship faucet is enabled if (chain.faucet?.enabled && chain.faucet.type === 'starship') { volumes.push({ name: 'faucet', emptyDir: {} }); } // Add proposal volume if ICS is enabled if (chain.ics?.enabled) { volumes.push({ name: 'proposal', configMap: { name: `consumer-proposal-${getChainName(String(chain.id))}` } }); } return volumes; } exports.generateChainVolumes = generateChainVolumes; function getHostname(chain) { return getChainName(String(chain.id)); } exports.getHostname = getHostname; function getChainId(chain) { return String(chain.id); } exports.getChainId = getChainId;