@starship-ci/generator
Version:
Kubernetes manifest generator for Starship deployments
387 lines (386 loc) • 11.9 kB
JavaScript
;
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;