diff --git a/doc/cli.markdown b/doc/cli.markdown index da71f9a5..c6b4ba97 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -1424,6 +1424,9 @@ Sample registry-secrets YAML file: username: '_json_key' password: '{escaped contents of the GCR keyfile.json file}' +If an option is not specified, and a secrets.yml or secrets.json file exists in +the balena directory (usually $HOME/.balena), this file will be used instead. + Examples: $ balena push myApp @@ -1459,7 +1462,9 @@ Don't use cache when building this project #### --registry-secrets, -R <secrets.yml|.json> -Path to a local YAML or JSON file containing Docker registry passwords used to pull base images +Path to a local YAML or JSON file containing Docker registry passwords used to pull base images. +Note that if registry-secrets are not provided on the command line, a secrets configuration +file from the balena directory will be used (usually $HOME/.balena/secrets.yml|.json) #### --nolive @@ -1566,6 +1571,9 @@ Sample registry-secrets YAML file: username: '_json_key' password: '{escaped contents of the GCR keyfile.json file}' +If an option is not specified, and a secrets.yml or secrets.json file exists in +the balena directory (usually $HOME/.balena), this file will be used instead. + Examples: $ balena build @@ -1687,6 +1695,9 @@ Sample registry-secrets YAML file: username: '_json_key' password: '{escaped contents of the GCR keyfile.json file}' +If an option is not specified, and a secrets.yml or secrets.json file exists in +the balena directory (usually $HOME/.balena), this file will be used instead. + Examples: $ balena deploy myApp diff --git a/lib/actions/build.coffee b/lib/actions/build.coffee index ec6db920..44f4d0ad 100644 --- a/lib/actions/build.coffee +++ b/lib/actions/build.coffee @@ -101,6 +101,8 @@ module.exports = action: (params, options, done) -> # compositions with many services trigger misleading warnings require('events').defaultMaxListeners = 1000 + + sdk = (require('balena-sdk')).fromSharedOptions() { validateComposeOptions } = require('../utils/compose_ts') { exitWithExpectedError } = require('../utils/patterns') helpers = require('../utils/helpers') @@ -116,7 +118,7 @@ module.exports = options.source ?= params.source delete params.source - validateComposeOptions(options) + validateComposeOptions(sdk, options) { application, arch, deviceType } = options diff --git a/lib/actions/deploy.coffee b/lib/actions/deploy.coffee index afc49461..a34340e1 100644 --- a/lib/actions/deploy.coffee +++ b/lib/actions/deploy.coffee @@ -180,6 +180,7 @@ module.exports = action: (params, options, done) -> # compositions with many services trigger misleading warnings require('events').defaultMaxListeners = 1000 + sdk = (require('balena-sdk')).fromSharedOptions() { validateComposeOptions } = require('../utils/compose_ts') helpers = require('../utils/helpers') Logger = require('../utils/logger') @@ -198,7 +199,7 @@ module.exports = appName = appName_raw || appName || options.application delete options.application - validateComposeOptions(options) + validateComposeOptions(sdk, options) if not appName? throw new Error('Please specify the name of the application to deploy') diff --git a/lib/actions/push.ts b/lib/actions/push.ts index 3157d82b..480381ba 100644 --- a/lib/actions/push.ts +++ b/lib/actions/push.ts @@ -194,7 +194,9 @@ export const push: CommandDefinition< alias: 'R', parameter: 'secrets.yml|.json', description: stripIndent` - Path to a local YAML or JSON file containing Docker registry passwords used to pull base images`, + Path to a local YAML or JSON file containing Docker registry passwords used to pull base images. + Note that if registry-secrets are not provided on the command line, a secrets configuration + file from the balena directory will be used (usually $HOME/.balena/secrets.yml|.json)`, }, { signature: 'nolive', @@ -248,7 +250,7 @@ export const push: CommandDefinition< const { exitIfNotLoggedIn, exitWithExpectedError } = await import( '../utils/patterns' ); - const { validateSpecifiedDockerfile, parseRegistrySecrets } = await import( + const { validateSpecifiedDockerfile, getRegistrySecrets } = await import( '../utils/compose_ts' ); const { BuildError } = await import('../utils/device/errors'); @@ -269,9 +271,10 @@ export const push: CommandDefinition< options.dockerfile, ); - const registrySecrets = options['registry-secrets'] - ? await parseRegistrySecrets(options['registry-secrets']) - : {}; + const registrySecrets = await getRegistrySecrets( + sdk, + options['registry-secrets'], + ); const buildTarget = getBuildTarget(appOrDevice); switch (buildTarget) { diff --git a/lib/utils/compose_ts.ts b/lib/utils/compose_ts.ts index d25d67ef..c08e3b6a 100644 --- a/lib/utils/compose_ts.ts +++ b/lib/utils/compose_ts.ts @@ -21,6 +21,7 @@ import * as MultiBuild from 'resin-multibuild'; import { Readable } from 'stream'; import * as tar from 'tar-stream'; +import { BalenaSDK } from 'balena-sdk'; import { DeviceInfo } from './device/api'; import Logger = require('./logger'); @@ -31,7 +32,34 @@ export interface RegistrySecrets { }; } -export async function parseRegistrySecrets( +export async function getRegistrySecrets( + sdk: BalenaSDK, + inputFilename?: string, +): Promise { + const { fs } = await import('mz'); + const Path = await import('path'); + + if (inputFilename != null) { + return await parseRegistrySecrets(inputFilename); + } + + const directory = await sdk.settings.get('dataDirectory'); + const potentialPaths = [ + Path.join(directory, 'secrets.yml'), + Path.join(directory, 'secrets.yaml'), + Path.join(directory, 'secrets.json'), + ]; + + for (const path of potentialPaths) { + if (await fs.exists(path)) { + return await parseRegistrySecrets(path); + } + } + + return {}; +} + +async function parseRegistrySecrets( secretsFilename: string, ): Promise { const { fs } = await import('mz'); @@ -63,12 +91,14 @@ export async function parseRegistrySecrets( * This function is meant to be called very early on to validate users' input, * before any project loading / building / deploying. */ -export async function validateComposeOptions(options: { [opt: string]: any }) { - if (options['registry-secrets']) { - options['registry-secrets'] = await parseRegistrySecrets( - options['registry-secrets'], - ); - } +export async function validateComposeOptions( + sdk: BalenaSDK, + options: { [opt: string]: any }, +) { + options['registry-secrets'] = await getRegistrySecrets( + sdk, + options['registry-secrets'], + ); } /** diff --git a/lib/utils/messages.ts b/lib/utils/messages.ts index e5f8eaaa..0357785b 100644 --- a/lib/utils/messages.ts +++ b/lib/utils/messages.ts @@ -43,4 +43,7 @@ Sample registry-secrets YAML file: password: cze14 'eu.gcr.io': # Google Container Registry username: '_json_key' - password: '{escaped contents of the GCR keyfile.json file}'`; + password: '{escaped contents of the GCR keyfile.json file}' + +If an option is not specified, and a secrets.yml or secrets.json file exists in +the balena directory (usually $HOME/.balena), this file will be used instead.`;