@adobe/aio-cli-plugin-app 8.4.0 → 8.5.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +169 -146
- package/oclif.manifest.json +1 -1
- package/package.json +13 -12
- package/src/commands/app/config/get/index.js +25 -0
- package/src/commands/app/config/get/log-forwarding/errors.js +46 -0
- package/src/commands/app/config/get/log-forwarding.js +46 -0
- package/src/commands/app/config/index.js +25 -0
- package/src/commands/app/config/set/index.js +25 -0
- package/src/commands/app/config/set/log-forwarding.js +45 -0
- package/src/commands/app/deploy.js +39 -9
- package/src/commands/app/logs.js +10 -1
- package/src/commands/app/run.js +8 -6
- package/src/commands/app/undeploy.js +8 -6
- package/src/lib/deploy-actions.js +1 -1
- package/src/lib/log-forwarding.js +259 -0
|
@@ -72,12 +72,14 @@ class Undeploy extends BaseCommand {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
async undeployOneExt (extName, config, flags, spinner) {
|
|
75
|
-
const onProgress = !flags.verbose
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
const onProgress = !flags.verbose
|
|
76
|
+
? info => {
|
|
77
|
+
spinner.text = info
|
|
78
|
+
}
|
|
79
|
+
: info => {
|
|
80
|
+
spinner.info(chalk.dim(`${info}`))
|
|
81
|
+
spinner.start()
|
|
82
|
+
}
|
|
81
83
|
// undeploy
|
|
82
84
|
try {
|
|
83
85
|
await runScript(config.hooks['pre-app-undeploy'])
|
|
@@ -17,7 +17,7 @@ const { deployActions } = require('@adobe/aio-lib-runtime')
|
|
|
17
17
|
* Deploys actions.
|
|
18
18
|
*
|
|
19
19
|
* @param {object} config see src/lib/config-loader.js
|
|
20
|
-
* @param {boolean} isLocal
|
|
20
|
+
* @param {boolean} isLocal default false, set to true if it's a local deploy
|
|
21
21
|
* @param {Function} [log] a log function
|
|
22
22
|
* @param {boolean} filter true if a filter by built actions is desired.
|
|
23
23
|
*/
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const rtLib = require('@adobe/aio-lib-runtime')
|
|
14
|
+
const { writeAio, writeEnv } = require('./import')
|
|
15
|
+
const crypto = require('crypto')
|
|
16
|
+
const fs = require('fs-extra')
|
|
17
|
+
const path = require('path')
|
|
18
|
+
|
|
19
|
+
const SECRET_FIELD_TYPE = 'password'
|
|
20
|
+
const CHECKSUM_DIR = 'dist'
|
|
21
|
+
const CHECKSUM_FILE = 'log-forwarding-config.sha256'
|
|
22
|
+
const IGNORED_REMOTE_SETTINGS = ['updated_at']
|
|
23
|
+
|
|
24
|
+
class LogForwarding {
|
|
25
|
+
constructor (aioConfig) {
|
|
26
|
+
this.aioConfig = aioConfig
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async init () {
|
|
30
|
+
rtLib.utils.checkOpenWhiskCredentials({ ow: this.aioConfig.runtime })
|
|
31
|
+
this.logForwarding = await getRTLogForwarding(this.aioConfig.runtime)
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getLocalConfig () {
|
|
36
|
+
const config = this.aioConfig.project.workspace.log_forwarding
|
|
37
|
+
try {
|
|
38
|
+
return this.getConfigFromJson(config)
|
|
39
|
+
} catch (e) {
|
|
40
|
+
throw new Error('Incorrect local log forwarding configuration. ' + e.message)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getLocalConfigWithSecrets () {
|
|
45
|
+
const config = this.getLocalConfig()
|
|
46
|
+
const destination = config.getDestination()
|
|
47
|
+
const settings = config.getSettings()
|
|
48
|
+
if (config.isDefined()) {
|
|
49
|
+
const destinationSettings = this.logForwarding.getDestinationSettings(destination)
|
|
50
|
+
const missingSecrets = []
|
|
51
|
+
destinationSettings.forEach(e => {
|
|
52
|
+
if (e.type === SECRET_FIELD_TYPE) {
|
|
53
|
+
const secretVarName = getSecretVarName(destination, e.name)
|
|
54
|
+
if (process.env[secretVarName] !== undefined) {
|
|
55
|
+
settings[e.name] = process.env[secretVarName]
|
|
56
|
+
} else {
|
|
57
|
+
missingSecrets.push(secretVarName)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
if (missingSecrets.length > 0) {
|
|
62
|
+
throw new Error('Required secrets are missing in environment variables: ' + missingSecrets.join(', ') + '. ' +
|
|
63
|
+
'Make sure these variables are set in .env file')
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return new LogForwardingConfig(destination, settings)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async getServerConfig () {
|
|
70
|
+
try {
|
|
71
|
+
return this.getConfigFromJson(await this.logForwarding.get())
|
|
72
|
+
} catch (e) {
|
|
73
|
+
throw new Error('Incorrect log forwarding configuration on server. ' + e.message)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Convert JSON config to Log Forwarding object
|
|
79
|
+
*
|
|
80
|
+
* @param {object} configJson Config in JSON format
|
|
81
|
+
* @returns {LogForwardingConfig} Config
|
|
82
|
+
*/
|
|
83
|
+
getConfigFromJson (configJson) {
|
|
84
|
+
let destination
|
|
85
|
+
let settings
|
|
86
|
+
|
|
87
|
+
if (configJson !== undefined && configJson !== null && !Array.isArray(configJson) && typeof configJson === 'object') {
|
|
88
|
+
const destinations = Object.keys(configJson)
|
|
89
|
+
if (destinations.length === 1) {
|
|
90
|
+
destination = destinations[0]
|
|
91
|
+
settings = configJson[destination]
|
|
92
|
+
} else {
|
|
93
|
+
throw new Error(`Configuration has ${destinations.length} destinations. Exactly one must be defined.`)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return new LogForwardingConfig(destination, settings)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getSupportedDestinations () {
|
|
100
|
+
return this.logForwarding.getSupportedDestinations()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getSettingsConfig (destination) {
|
|
104
|
+
return this.logForwarding.getDestinationSettings(destination)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async updateLocalConfig (lfConfig) {
|
|
108
|
+
const destination = lfConfig.getDestination()
|
|
109
|
+
const destinationSettings = this.logForwarding.getDestinationSettings(destination)
|
|
110
|
+
const projectConfig = {
|
|
111
|
+
project: this.aioConfig.project
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const nonSecretSettings = {}
|
|
115
|
+
const secretSettings = {}
|
|
116
|
+
|
|
117
|
+
const settings = lfConfig.getSettings()
|
|
118
|
+
Object.keys(settings)
|
|
119
|
+
.filter(e => !IGNORED_REMOTE_SETTINGS.includes(e))
|
|
120
|
+
.forEach(k => {
|
|
121
|
+
const destFieldSettings = destinationSettings.find(i => i.name === k)
|
|
122
|
+
if (destFieldSettings.type === SECRET_FIELD_TYPE) {
|
|
123
|
+
secretSettings[getSecretVarName(destination, k)] = settings[k]
|
|
124
|
+
} else {
|
|
125
|
+
nonSecretSettings[k] = settings[k]
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
projectConfig.project.workspace.log_forwarding = {
|
|
130
|
+
[destination]: nonSecretSettings
|
|
131
|
+
}
|
|
132
|
+
const interactive = false
|
|
133
|
+
const merge = true
|
|
134
|
+
await writeAio(projectConfig, '', { interactive, merge })
|
|
135
|
+
await writeEnv({}, '', { interactive, merge }, secretSettings)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
isLocalConfigChanged () {
|
|
139
|
+
if (fs.pathExistsSync(path.join(CHECKSUM_DIR, CHECKSUM_FILE))) {
|
|
140
|
+
const oldChecksum = fs.readFileSync(path.join(CHECKSUM_DIR, CHECKSUM_FILE)).toString()
|
|
141
|
+
const config = this.getLocalConfigWithSecrets()
|
|
142
|
+
const newChecksum = getChecksum(config)
|
|
143
|
+
return oldChecksum !== newChecksum
|
|
144
|
+
} else {
|
|
145
|
+
return true
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async updateServerConfig (lfConfig) {
|
|
150
|
+
const res = await this.logForwarding.setDestination(lfConfig.getDestination(), lfConfig.getSettings())
|
|
151
|
+
const checksum = getChecksum(lfConfig)
|
|
152
|
+
fs.ensureDirSync(CHECKSUM_DIR)
|
|
153
|
+
fs.writeFile(path.join(CHECKSUM_DIR, CHECKSUM_FILE), checksum, { flags: 'w' })
|
|
154
|
+
return res
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
class LogForwardingConfig {
|
|
159
|
+
constructor (destination, settings) {
|
|
160
|
+
this.destination = destination
|
|
161
|
+
this.settings = settings
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
getDestination () {
|
|
165
|
+
return this.destination
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
getSettings () {
|
|
169
|
+
return this.settings
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
isDefined () {
|
|
173
|
+
return this.destination !== undefined
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
isDefault () {
|
|
177
|
+
return !this.isDefined() || this.getDestination() === 'adobe_io_runtime'
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
isEqual (config) {
|
|
181
|
+
return (this.isDefault() && config.isDefault()) ||
|
|
182
|
+
(this.destination === config.getDestination() && shallowEqual(this.settings, config.settings))
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Init Log Forwarding
|
|
188
|
+
*
|
|
189
|
+
* @param {object} aioConfig aio Config
|
|
190
|
+
* @returns {Promise<LogForwarding>} Log Forwarding
|
|
191
|
+
*/
|
|
192
|
+
async function init (aioConfig) {
|
|
193
|
+
const lf = new LogForwarding(aioConfig)
|
|
194
|
+
return await lf.init()
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get Runtime Log Forwarding
|
|
199
|
+
*
|
|
200
|
+
* @param {object} rtConfig Runtime config
|
|
201
|
+
* @returns {Promise<LogForwarding>} Log Forwarding
|
|
202
|
+
*/
|
|
203
|
+
async function getRTLogForwarding (rtConfig) {
|
|
204
|
+
const rt = await rtLib.init({
|
|
205
|
+
...rtConfig,
|
|
206
|
+
api_key: rtConfig.auth
|
|
207
|
+
})
|
|
208
|
+
return rt.logForwarding
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Compare to log forwarding configs
|
|
213
|
+
*
|
|
214
|
+
* @param {LogForwardingConfig} config1 Config
|
|
215
|
+
* @param {LogForwardingConfig} config2 Config
|
|
216
|
+
* @returns {boolean} Are configs equal
|
|
217
|
+
*/
|
|
218
|
+
function shallowEqual (config1, config2) {
|
|
219
|
+
// updated_at exists on server only and does not impact actual configuration
|
|
220
|
+
const keys1 = Object.keys(config1).filter(e => !IGNORED_REMOTE_SETTINGS.includes(e))
|
|
221
|
+
const keys2 = Object.keys(config2).filter(e => !IGNORED_REMOTE_SETTINGS.includes(e))
|
|
222
|
+
if (keys1.length !== keys2.length) {
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
for (const key of keys1) {
|
|
226
|
+
if (config1[key] !== config2[key]) {
|
|
227
|
+
return false
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return true
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get secret variable name for the given destination and settings field
|
|
235
|
+
*
|
|
236
|
+
* @param {string} destination Destination
|
|
237
|
+
* @param {string} fieldName Field name
|
|
238
|
+
* @returns {string} Variable name
|
|
239
|
+
*/
|
|
240
|
+
function getSecretVarName (destination, fieldName) {
|
|
241
|
+
return destination.toUpperCase() + '__' + fieldName.toUpperCase()
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Generate checksum for the config
|
|
246
|
+
*
|
|
247
|
+
* @param {LogForwardingConfig} config Config
|
|
248
|
+
* @returns {string} Checksum
|
|
249
|
+
*/
|
|
250
|
+
function getChecksum (config) {
|
|
251
|
+
return crypto.createHash('sha256')
|
|
252
|
+
.update(JSON.stringify(config))
|
|
253
|
+
.digest('hex')
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = {
|
|
257
|
+
init,
|
|
258
|
+
LogForwardingConfig
|
|
259
|
+
}
|