diff --git a/packages/cli/src/commands/telemetry/add.ts b/packages/cli/src/commands/telemetry/add.ts index aa2ca9f9fb..bc7eb89723 100644 --- a/packages/cli/src/commands/telemetry/add.ts +++ b/packages/cli/src/commands/telemetry/add.ts @@ -3,6 +3,8 @@ import {Args, ux} from '@oclif/core' import {TelemetryDrain} from '../../lib/types/telemetry' import heredoc from 'tsheredoc' import {validateAndFormatSignals} from '../../lib/telemetry/util' +import {App, Space} from '@heroku-cli/schema' + export default class Add extends Command { static description = 'Add and configure a new telemetry drain. Defaults to collecting all telemetry unless otherwise specified.' @@ -21,26 +23,29 @@ export default class Add extends Command { static example = heredoc(` Add a telemetry drain to an app to collect logs and traces: - $ heroku telemetry:add --signals logs,traces --endpoint https://my-endpoint.com --transport http 'x-drain-example-team: API_KEY x-drain-example-dataset: METRICS_DATASET' + $ heroku telemetry:add --app myapp --signals logs,traces --endpoint https://my-endpoint.com --transport http '{"x-drain-example-team": "API_KEY", "x-drain-example-dataset": "METRICS_DATASET"}' `) - private getTypeAndName = function (app: string | undefined, space: string | undefined) { - if (app) { - return {type: 'app', name: app} - } - - return {type: 'space', name: space} - } - public async run(): Promise { const {flags, args} = await this.parse(Add) const {app, space, signals, endpoint, transport} = flags const {headers} = args - const typeAndName = this.getTypeAndName(app, space) + let id + if (app) { + const {body: herokuApp} = await this.heroku.get( + `/apps/${app}`, { + headers: {Accept: 'application/vnd.heroku+json; version=3.sdk'}, + }) + id = herokuApp.id + } else { + const {body: herokuSpace} = await this.heroku.get(`/spaces/${space}`) + id = herokuSpace.id + } + const drainConfig = { owner: { - type: typeAndName.type, - id: typeAndName.name, + type: app ? 'app' : 'space', + id, }, signals: validateAndFormatSignals(signals), exporter: { @@ -50,24 +55,13 @@ export default class Add extends Command { }, } - if (app) { - const {body: drain} = await this.heroku.post(`/apps/${app}/telemetry-drains`, { - body: drainConfig, - headers: { - Accept: 'application/vnd.heroku+json; version=3.sdk', - }, - }) - - ux.log(`successfully added drain ${drain.exporter.endpoint}`) - } else if (space) { - const {body: drain} = await this.heroku.post(`/spaces/${space}/telemetry-drains`, { - body: drainConfig, - headers: { - Accept: 'application/vnd.heroku+json; version=3.sdk', - }, - }) + const {body: drain} = await this.heroku.post('/telemetry-drains', { + body: drainConfig, + headers: { + Accept: 'application/vnd.heroku+json; version=3.sdk', + }, + }) - ux.log(`successfully added drain ${drain.exporter.endpoint}`) - } + ux.log(`successfully added drain ${drain.exporter.endpoint}`) } } diff --git a/packages/cli/src/commands/telemetry/index.ts b/packages/cli/src/commands/telemetry/index.ts index bde413b204..e478290c0d 100644 --- a/packages/cli/src/commands/telemetry/index.ts +++ b/packages/cli/src/commands/telemetry/index.ts @@ -15,34 +15,39 @@ export default class Index extends Command { public async run(): Promise { const {flags} = await this.parse(Index) const {app, space} = flags - + let drains: TelemetryDrains = [] if (app) { const {body: appTelemetryDrains} = await this.heroku.get(`/apps/${app}/telemetry-drains`, { headers: { Accept: 'application/vnd.heroku+json; version=3.sdk', }, }) - this.display(appTelemetryDrains, 'App') + drains = appTelemetryDrains } else if (space) { const {body: spaceTelemetryDrains} = await this.heroku.get(`/spaces/${space}/telemetry-drains`, { headers: { Accept: 'application/vnd.heroku+json; version=3.sdk', }, }) - this.display(spaceTelemetryDrains, 'Space') + drains = spaceTelemetryDrains } + + this.display(drains, app || space) } - protected display(telemetryDrains: TelemetryDrains, ownerType: 'App' | 'Space') { - ux.styledHeader(`${ownerType} Telemetry Drains`) - ux.table( - telemetryDrains, - { - ID: {get: telemetryDrain => telemetryDrain.id}, - Signals: {get: telemetryDrain => telemetryDrain.signals}, - Endpoint: {get: telemetryDrain => telemetryDrain.exporter.endpoint}, - [ownerType]: {get: telemetryDrain => telemetryDrain.owner.name}, - }, - ) + protected display(telemetryDrains: TelemetryDrains, owner: string | undefined) { + if (telemetryDrains.length === 0) { + ux.log(`There are no telemetry drains in ${owner}`) + } else { + ux.styledHeader(`${owner} Telemetry Drains`) + ux.table( + telemetryDrains, + { + ID: {get: telemetryDrain => telemetryDrain.id}, + Signals: {get: telemetryDrain => telemetryDrain.signals}, + Endpoint: {get: telemetryDrain => telemetryDrain.exporter.endpoint}, + }, + ) + } } } diff --git a/packages/cli/src/commands/telemetry/remove.ts b/packages/cli/src/commands/telemetry/remove.ts index 833cd7413a..19d766e0ce 100644 --- a/packages/cli/src/commands/telemetry/remove.ts +++ b/packages/cli/src/commands/telemetry/remove.ts @@ -27,8 +27,8 @@ export default class Remove extends Command { } if (telemetry_drain_id) { - const telemetryDrain = await this.removeDrain(telemetry_drain_id) - ux.action.start(`Removing telemetry drain ${telemetry_drain_id}, which was configured for ${telemetryDrain.owner.type} ${telemetryDrain.owner.name}`) + ux.action.start(`Removing telemetry drain ${telemetry_drain_id}`) + await this.removeDrain(telemetry_drain_id) } else if (app) { ux.action.start(`Removing all telemetry drains from app ${app}`) const {body: telemetryDrains} = await this.heroku.get(`/apps/${app}/telemetry-drains`, { diff --git a/packages/cli/test/unit/commands/telemetry/add.unit.test.ts b/packages/cli/test/unit/commands/telemetry/add.unit.test.ts index 0feb6365a3..a1825264c9 100644 --- a/packages/cli/test/unit/commands/telemetry/add.unit.test.ts +++ b/packages/cli/test/unit/commands/telemetry/add.unit.test.ts @@ -5,12 +5,21 @@ import {expect} from 'chai' import * as nock from 'nock' import expectOutput from '../../../helpers/utils/expectOutput' import {spaceTelemetryDrain1, appTelemetryDrain1} from '../../../fixtures/telemetry/fixtures' +import {firApp} from '../../../fixtures/apps/fixtures' +import * as spaceFixtures from '../../../fixtures/spaces/fixtures' +import {SpaceWithOutboundIps} from '../../../../src/lib/types/spaces' const appId = appTelemetryDrain1.owner.id const spaceId = spaceTelemetryDrain1.owner.id const testEndpoint = appTelemetryDrain1.exporter.endpoint describe('telemetry:add', function () { + let space: SpaceWithOutboundIps + + beforeEach(function () { + space = spaceFixtures.spaces['non-shield-space'] + }) + afterEach(function () { return nock.cleanAll() }) @@ -31,7 +40,7 @@ describe('telemetry:add', function () { await runCommand(Cmd, [ '{"x-honeycomb-team": "your-api-key", "x-honeycomb-dataset": "your-dataset"}', '--app', - 'myapp', + firApp.name || '', '--space', 'myspace', ]) @@ -43,7 +52,10 @@ describe('telemetry:add', function () { it('successfully creates a telemetry drain for an app', async function () { nock('https://api.heroku.com', {reqheaders: {Accept: 'application/vnd.heroku+json; version=3.sdk'}}) - .post(`/apps/${appId}/telemetry-drains`) + .get(`/apps/${appId}`) + .reply(200, firApp) + nock('https://api.heroku.com', {reqheaders: {Accept: 'application/vnd.heroku+json; version=3.sdk'}}) + .post('/telemetry-drains') .reply(200, spaceTelemetryDrain1) await runCommand(Cmd, [ @@ -62,8 +74,11 @@ describe('telemetry:add', function () { }) it('successfully creates a telemetry drain for a space', async function () { + nock('https://api.heroku.com') + .get(`/spaces/${spaceId}`) + .reply(200, space) nock('https://api.heroku.com', {reqheaders: {Accept: 'application/vnd.heroku+json; version=3.sdk'}}) - .post(`/spaces/${spaceId}/telemetry-drains`) + .post('/telemetry-drains') .reply(200, spaceTelemetryDrain1) await runCommand(Cmd, [ @@ -82,6 +97,9 @@ describe('telemetry:add', function () { }) it('does not accept options other than logs, metrics, traces, or all for the --signal flag', async function () { + nock('https://api.heroku.com') + .get(`/spaces/${spaceId}`) + .reply(200, space) try { await runCommand(Cmd, [ '{"x-honeycomb-team": "your-api-key", "x-honeycomb-dataset": "your-dataset"}', @@ -101,6 +119,9 @@ describe('telemetry:add', function () { }) it('returns an error when the --signal flag is set to "all" in combination with other options', async function () { + nock('https://api.heroku.com') + .get(`/spaces/${spaceId}`) + .reply(200, space) try { await runCommand(Cmd, [ '{"x-honeycomb-team": "your-api-key", "x-honeycomb-dataset": "your-dataset"}', diff --git a/packages/cli/test/unit/commands/telemetry/index.unit.test.ts b/packages/cli/test/unit/commands/telemetry/index.unit.test.ts index 6152b47087..bec9e2ed48 100644 --- a/packages/cli/test/unit/commands/telemetry/index.unit.test.ts +++ b/packages/cli/test/unit/commands/telemetry/index.unit.test.ts @@ -34,10 +34,10 @@ describe('telemetry:index', function () { spaceId, ]) expectOutput(stdout.output, heredoc(` - === Space Telemetry Drains - Id Signals Endpoint Space - ──────────────────────────────────── ─────────────────────────────── ───────────────────────── ─────── - 44444321-5717-4562-b3fc-2c963f66afa6 [ 'traces', 'metrics', 'logs' ] https://api.honeycomb.io/ myspace + === ${spaceId} Telemetry Drains + Id Signals Endpoint + ──────────────────────────────────── ─────────────────────────────── ───────────────────────── + 44444321-5717-4562-b3fc-2c963f66afa6 [ 'traces', 'metrics', 'logs' ] https://api.honeycomb.io/ `)) }) @@ -51,11 +51,25 @@ describe('telemetry:index', function () { appId, ]) expectOutput(stdout.output, heredoc(` - === App Telemetry Drains - Id Signals Endpoint App - ──────────────────────────────────── ─────────────────────── ─────────────────────────── ───── - 3fa85f64-5717-4562-b3fc-2c963f66afa6 [ 'traces', 'metrics' ] https://api.honeycomb.io/ myapp - 55555f64-5717-4562-b3fc-2c963f66afa6 [ 'logs' ] https://api.papertrail.com/ myapp + === ${appId} Telemetry Drains + Id Signals Endpoint + ──────────────────────────────────── ─────────────────────── ─────────────────────────── + 3fa85f64-5717-4562-b3fc-2c963f66afa6 [ 'traces', 'metrics' ] https://api.honeycomb.io/ + 55555f64-5717-4562-b3fc-2c963f66afa6 [ 'logs' ] https://api.papertrail.com/ + `)) + }) + + it('shows a message when there are no telemetry drains', async function () { + nock('https://api.heroku.com', {reqheaders: {Accept: 'application/vnd.heroku+json; version=3.sdk'}}) + .get(`/apps/${appId}/telemetry-drains`) + .reply(200, []) + + await runCommand(Cmd, [ + '--app', + appId, + ]) + expectOutput(stdout.output, heredoc(` + There are no telemetry drains in ${appId} `)) }) }) diff --git a/packages/cli/test/unit/commands/telemetry/remove.unit.test.ts b/packages/cli/test/unit/commands/telemetry/remove.unit.test.ts index a0e9c0939c..6fe3e33a45 100644 --- a/packages/cli/test/unit/commands/telemetry/remove.unit.test.ts +++ b/packages/cli/test/unit/commands/telemetry/remove.unit.test.ts @@ -37,8 +37,8 @@ describe('telemetry:remove', function () { spaceTelemetryDrain1.id, ]) expectOutput(stderr.output, heredoc(` - Removing telemetry drain ${spaceTelemetryDrain1.id}, which was configured for space ${spaceTelemetryDrain1.owner.name}... - Removing telemetry drain ${spaceTelemetryDrain1.id}, which was configured for space ${spaceTelemetryDrain1.owner.name}... done + Removing telemetry drain ${spaceTelemetryDrain1.id}... + Removing telemetry drain ${spaceTelemetryDrain1.id}... done `)) }) @@ -54,8 +54,8 @@ describe('telemetry:remove', function () { appTelemetryDrain1.id, ]) expectOutput(stderr.output, heredoc(` - Removing telemetry drain ${appTelemetryDrain1.id}, which was configured for app ${appTelemetryDrain1.owner.name}... - Removing telemetry drain ${appTelemetryDrain1.id}, which was configured for app ${appTelemetryDrain1.owner.name}... done + Removing telemetry drain ${appTelemetryDrain1.id}... + Removing telemetry drain ${appTelemetryDrain1.id}... done `)) })