UNPKG

heroku-kafka

Version:
115 lines (114 loc) 3.74 kB
import { color } from '@heroku/heroku-cli-util'; import { ux } from '@oclif/core'; import debug from './debug.js'; import fetcher from './fetcher.js'; import host from './host.js'; const VERSION = 'v0'; class HerokuKafkaClusters { app; context; env; heroku; constructor(heroku, env, context) { this.heroku = heroku; this.env = env; this.context = context; this.app = context.app; } request(params) { const h = host(); debug(`picked shogun host: ${h}`); const { path, method, body, ...rest } = params; const url = `https://${h}${path}`; return this.heroku.request(url, { method: method || 'GET', body, headers: { accept: params.accept || 'application/json', }, ...rest, }); } async waitStatus(addon) { const errorResponse = { message: 'unknown', 'waiting?': true, 'healthy?': false, }; if (!addon) { return null; } const response = await this.request({ path: `/data/kafka/${VERSION}/clusters/${addon.id}/wait_status`, }).then((res) => res.body || res) .catch((error) => { if (error.statusCode === 410) { return { 'deprovisioned?': true, ...errorResponse }; } if (error.statusCode === 404) { return { 'missing?': true, ...errorResponse }; } return errorResponse; }); return response; } } // Looks up cluster by name. Name is optional, but only one cluster // must exit on the app if it is omitted. async function withCluster(heroku, app, cluster, fn) { const fetch = fetcher(heroku); let addon; if (cluster) { addon = await fetch.addon(app, cluster); } else { const addons = await fetch.all(app); if (addons.length === 1) { addon = addons[0]; } else if (addons.length === 0) { ux.error(`found no kafka add-ons on ${app}`); } else { ux.error(`found more than one kafka add-on on ${app}: ${addons.map(addon => addon.name).join(', ')}`); } } return await fn(addon); } async function topicConfig(heroku, addonId, topic) { const response = await request(heroku, { path: `/data/kafka/${VERSION}/clusters/${addonId}/topics`, }); const info = (response?.body || response); const forTopic = info.topics.find(t => t.name === topic || ((t.prefix || '') + t.name) === topic); if (!forTopic) { ux.error(`topic ${topic} not found`); } return forTopic; } // Fetch kafka info about a provisioned cluster or exit with failure function fetchProvisionedInfo(heroku, addon) { const url = `https://${host()}/data/kafka/v0/clusters/${addon.id}`; return heroku.request(url, { method: 'GET' }) .then((res) => res.body || res) .catch((error) => { if (error.statusCode !== 404) throw error; ux.error(`${color.addon(addon.name)} is not yet provisioned.\nRun ${color.command('heroku kafka:wait')} to wait until the cluster is provisioned.`); }); } function request(heroku, params) { const h = host(); debug(`picked shogun host: ${h}`); const { path, method, body, ...rest } = params; const url = `https://${h}${path}`; return heroku.request(url, { method: method || 'GET', body, headers: { accept: params.accept || 'application/json', }, ...rest, }); } export { fetchProvisionedInfo, HerokuKafkaClusters, request, topicConfig, withCluster, };