1 | 'use strict'
|
2 |
|
3 | const co = require('co')
|
4 | const cli = require('heroku-cli-util')
|
5 | const sortBy = require('lodash.sortby')
|
6 | const printf = require('printf')
|
7 |
|
8 | function * run (context, heroku) {
|
9 | const fetcher = require('../lib/fetcher')(heroku)
|
10 |
|
11 | const {app, args, flags} = context
|
12 |
|
13 | let showCredentials = co.wrap(function * () {
|
14 | const host = require('../lib/host')
|
15 | let addon = yield fetcher.addon(app, args.database)
|
16 | let attachments = []
|
17 |
|
18 | function formatAttachment (attachment) {
|
19 | let attName = cli.color.addon(attachment.name)
|
20 |
|
21 | let output = [cli.color.dim('as'), attName]
|
22 | let appInfo = `on ${cli.color.app(attachment.app.name)} app`
|
23 | output.push(cli.color.dim(appInfo))
|
24 |
|
25 | return output.join(' ')
|
26 | }
|
27 |
|
28 | function renderAttachment (attachment, app, isLast) {
|
29 | let line = isLast ? '└─' : '├─'
|
30 | let attName = formatAttachment(attachment)
|
31 | return printf(' %s %s', cli.color.dim(line), attName)
|
32 | }
|
33 |
|
34 | function presentCredential (cred) {
|
35 | let credAttachments = []
|
36 | if (cred !== 'default') {
|
37 | credAttachments = attachments.filter(a => a.namespace === `credential:${cred}`)
|
38 | } else {
|
39 | credAttachments = attachments.filter(a => a.namespace === null)
|
40 | }
|
41 | let isForeignApp = (attOrAddon) => attOrAddon.app.name !== app
|
42 | let atts = sortBy(credAttachments,
|
43 | isForeignApp,
|
44 | 'name',
|
45 | 'app.name'
|
46 | )
|
47 |
|
48 |
|
49 | let attLines = atts.map(function (attachment, idx) {
|
50 | let isLast = (idx === credAttachments.length - 1)
|
51 | return renderAttachment(attachment, app, isLast)
|
52 | })
|
53 |
|
54 | return [cred].concat(attLines).join('\n')
|
55 | }
|
56 |
|
57 | try {
|
58 | let credentials = yield heroku.get(`/postgres/v0/databases/${addon.name}/credentials`,
|
59 | { host: host(addon) })
|
60 | let isDefaultCredential = (cred) => cred.name !== 'default'
|
61 | credentials = sortBy(credentials, isDefaultCredential, 'name')
|
62 | attachments = yield heroku.get(`/addons/${addon.name}/addon-attachments`)
|
63 |
|
64 | cli.table(credentials, {
|
65 | columns: [
|
66 | {key: 'name', label: 'Credential', format: presentCredential},
|
67 | {key: 'state', label: 'State'}
|
68 | ]
|
69 | })
|
70 | } catch (err) {
|
71 | if (!err.statusCode || err.statusCode !== 422) throw err
|
72 | let db = yield fetcher.database(app, args.database)
|
73 | cli.log(`Connection info string:
|
74 | "dbname=${db.database} host=${db.host} port=${db.port || 5432} user=${db.user} password=${db.password} sslmode=require"
|
75 | Connection URL:
|
76 | ${db.url.href}`)
|
77 | }
|
78 | })
|
79 |
|
80 | let reset = co.wrap(function * () {
|
81 | const host = require('../lib/host')
|
82 | let db = yield fetcher.addon(app, args.database)
|
83 | yield cli.action(`Resetting credentials on ${cli.color.addon(db.name)}`, co(function * () {
|
84 | yield heroku.post(`/client/v11/databases/${db.id}/credentials_rotation`, {host: host(db)})
|
85 | }))
|
86 | })
|
87 |
|
88 | if (flags.reset) {
|
89 | yield reset()
|
90 | } else {
|
91 | yield showCredentials()
|
92 | }
|
93 | }
|
94 |
|
95 | module.exports = {
|
96 | topic: 'pg',
|
97 | command: 'credentials',
|
98 | description: 'manage the database credentials',
|
99 | needsApp: true,
|
100 | needsAuth: true,
|
101 | flags: [{name: 'reset', description: 'reset database credentials'}],
|
102 | args: [{name: 'database', optional: true}],
|
103 | run: cli.command({preauth: true}, co.wrap(run))
|
104 | }
|