mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-02-06 11:10:10 +00:00
convert commands key
, keys
, key add
, key rm
to oclif.
Also: - Display keys with `name` instead of `title`. - Check for empty key before calling API. Change-type: patch Signed-off-by: Scott Lowe <scott@balena.io>
This commit is contained in:
parent
7c9a23451b
commit
be82bcfa63
@ -68,7 +68,12 @@ const capitanoDoc = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Keys',
|
title: 'Keys',
|
||||||
files: ['build/actions/keys.js'],
|
files: [
|
||||||
|
'build/actions-oclif/keys.js',
|
||||||
|
'build/actions-oclif/key/index.js',
|
||||||
|
'build/actions-oclif/key/add.js',
|
||||||
|
'build/actions-oclif/key/rm.js',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Logs',
|
title: 'Logs',
|
||||||
|
@ -190,8 +190,8 @@ If you come across any problems or would like to get in touch:
|
|||||||
|
|
||||||
- [keys](#keys)
|
- [keys](#keys)
|
||||||
- [key <id>](#key-id)
|
- [key <id>](#key-id)
|
||||||
- [key rm <id>](#key-rm-id)
|
|
||||||
- [key add <name> [path]](#key-add-name-path)
|
- [key add <name> [path]](#key-add-name-path)
|
||||||
|
- [key rm <id>](#key-rm-id)
|
||||||
|
|
||||||
- Logs
|
- Logs
|
||||||
|
|
||||||
@ -1063,41 +1063,33 @@ output version information in JSON format for programmatic use
|
|||||||
|
|
||||||
## keys
|
## keys
|
||||||
|
|
||||||
Use this command to list all your SSH keys.
|
List all SSH keys registered in balenaCloud for the logged in user.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
$ balena keys
|
$ balena keys
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
## key <id>
|
## key <id>
|
||||||
|
|
||||||
Use this command to show information about a single SSH key.
|
Display a single SSH key registered in balenaCloud for the logged in user.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
$ balena key 17
|
$ balena key 17
|
||||||
|
|
||||||
## key rm <id>
|
### Arguments
|
||||||
|
|
||||||
Use this command to remove a SSH key from balena.
|
#### ID
|
||||||
|
|
||||||
Notice this command asks for confirmation interactively.
|
balenaCloud ID for the SSH key
|
||||||
You can avoid this by passing the `--yes` boolean option.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena key rm 17
|
|
||||||
$ balena key rm 17 --yes
|
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
#### --yes, -y
|
|
||||||
|
|
||||||
confirm non interactively
|
|
||||||
|
|
||||||
## key add <name> [path]
|
## key add <name> [path]
|
||||||
|
|
||||||
Use this command to associate a new SSH key with your account.
|
Register an SSH in balenaCloud for the logged in user.
|
||||||
|
|
||||||
If `path` is omitted, the command will attempt
|
If `path` is omitted, the command will attempt
|
||||||
to read the SSH key from stdin.
|
to read the SSH key from stdin.
|
||||||
@ -1107,6 +1099,41 @@ Examples:
|
|||||||
$ balena key add Main ~/.ssh/id_rsa.pub
|
$ balena key add Main ~/.ssh/id_rsa.pub
|
||||||
$ cat ~/.ssh/id_rsa.pub | balena key add Main
|
$ cat ~/.ssh/id_rsa.pub | balena key add Main
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### NAME
|
||||||
|
|
||||||
|
the SSH key name
|
||||||
|
|
||||||
|
#### PATH
|
||||||
|
|
||||||
|
the path to the public key file
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
## key rm <id>
|
||||||
|
|
||||||
|
Remove a single SSH key registered in balenaCloud for the logged in user.
|
||||||
|
|
||||||
|
The --yes option may be used to avoid interactive confirmation.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena key rm 17
|
||||||
|
$ balena key rm 17 --yes
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### ID
|
||||||
|
|
||||||
|
balenaCloud ID for the SSH key
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### -y, --yes
|
||||||
|
|
||||||
|
answer "yes" to all questions (non interactive use)
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
|
|
||||||
## logs <uuidOrDevice>
|
## logs <uuidOrDevice>
|
||||||
|
3
lib/actions-oclif/env/rename.ts
vendored
3
lib/actions-oclif/env/rename.ts
vendored
@ -22,6 +22,7 @@ import * as cf from '../../utils/common-flags';
|
|||||||
import * as ec from '../../utils/env-common';
|
import * as ec from '../../utils/env-common';
|
||||||
import { getBalenaSdk } from '../../utils/lazy';
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
import { CommandHelp } from '../../utils/oclif-utils';
|
import { CommandHelp } from '../../utils/oclif-utils';
|
||||||
|
import { parseAsInteger } from '../../utils/validation';
|
||||||
|
|
||||||
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
||||||
|
|
||||||
@ -60,7 +61,7 @@ export default class EnvRenameCmd extends Command {
|
|||||||
name: 'id',
|
name: 'id',
|
||||||
required: true,
|
required: true,
|
||||||
description: "variable's numeric database ID",
|
description: "variable's numeric database ID",
|
||||||
parse: input => ec.parseDbId(input),
|
parse: input => parseAsInteger(input, 'id'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'value',
|
name: 'value',
|
||||||
|
3
lib/actions-oclif/env/rm.ts
vendored
3
lib/actions-oclif/env/rm.ts
vendored
@ -22,6 +22,7 @@ import Command from '../../command';
|
|||||||
import * as ec from '../../utils/env-common';
|
import * as ec from '../../utils/env-common';
|
||||||
import { getBalenaSdk } from '../../utils/lazy';
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
import { CommandHelp } from '../../utils/oclif-utils';
|
import { CommandHelp } from '../../utils/oclif-utils';
|
||||||
|
import { parseAsInteger } from '../../utils/validation';
|
||||||
|
|
||||||
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
||||||
|
|
||||||
@ -63,7 +64,7 @@ export default class EnvRmCmd extends Command {
|
|||||||
name: 'id',
|
name: 'id',
|
||||||
required: true,
|
required: true,
|
||||||
description: "variable's numeric database ID",
|
description: "variable's numeric database ID",
|
||||||
parse: input => ec.parseDbId(input),
|
parse: input => parseAsInteger(input, 'id'),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
87
lib/actions-oclif/key/add.ts
Normal file
87
lib/actions-oclif/key/add.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2016-2020 Balena Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { flags } from '@oclif/command';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import { ExpectedError } from '../../errors';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class KeyAddCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Add an SSH key to balenaCloud.
|
||||||
|
|
||||||
|
Register an SSH in balenaCloud for the logged in user.
|
||||||
|
|
||||||
|
If \`path\` is omitted, the command will attempt
|
||||||
|
to read the SSH key from stdin.
|
||||||
|
`;
|
||||||
|
|
||||||
|
public static examples = [
|
||||||
|
'$ balena key add Main ~/.ssh/id_rsa.pub',
|
||||||
|
'$ cat ~/.ssh/id_rsa.pub | balena key add Main',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static args = [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
description: 'the SSH key name',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `path`,
|
||||||
|
description: `the path to the public key file`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'key add <name> [path]';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public static readStdin = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params } = this.parse<FlagsDef, ArgsDef>(KeyAddCmd);
|
||||||
|
|
||||||
|
let key: string;
|
||||||
|
if (params.path != null) {
|
||||||
|
const { promisify } = await import('util');
|
||||||
|
const readFileAsync = promisify((await import('fs')).readFile);
|
||||||
|
key = await readFileAsync(params.path, 'utf8');
|
||||||
|
} else if (this.stdin.length > 0) {
|
||||||
|
key = this.stdin;
|
||||||
|
} else {
|
||||||
|
throw new ExpectedError('No public key file or path provided.');
|
||||||
|
}
|
||||||
|
|
||||||
|
await getBalenaSdk().models.key.create(params.name, key);
|
||||||
|
}
|
||||||
|
}
|
79
lib/actions-oclif/key/index.ts
Normal file
79
lib/actions-oclif/key/index.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2016-2020 Balena Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { flags } from '@oclif/command';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { getBalenaSdk, getVisuals } from '../../utils/lazy';
|
||||||
|
import { parseAsInteger } from '../../utils/validation';
|
||||||
|
|
||||||
|
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class KeyCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Display an SSH key.
|
||||||
|
|
||||||
|
Display a single SSH key registered in balenaCloud for the logged in user.
|
||||||
|
`;
|
||||||
|
|
||||||
|
public static examples = ['$ balena key 17'];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
description: 'balenaCloud ID for the SSH key',
|
||||||
|
parse: x => parseAsInteger(x, 'id'),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'key <id>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params } = this.parse<{}, ArgsDef>(KeyCmd);
|
||||||
|
|
||||||
|
const key = await getBalenaSdk().models.key.get(params.id);
|
||||||
|
|
||||||
|
// Use 'name' instead of 'title' to match dashboard.
|
||||||
|
const displayKey = {
|
||||||
|
id: key.id,
|
||||||
|
name: key.title,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(getVisuals().table.vertical(displayKey, ['id', 'name']));
|
||||||
|
|
||||||
|
// Since the public key string is long, it might
|
||||||
|
// wrap to lines below, causing the table layout to break.
|
||||||
|
// See https://github.com/balena-io/balena-cli/issues/151
|
||||||
|
console.log('\n' + key.public_key);
|
||||||
|
}
|
||||||
|
}
|
79
lib/actions-oclif/key/rm.ts
Normal file
79
lib/actions-oclif/key/rm.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2016-2020 Balena Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { flags } from '@oclif/command';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
|
import { parseAsInteger } from '../../utils/validation';
|
||||||
|
|
||||||
|
type IArg<T> = import('@oclif/parser').args.IArg<T>;
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
yes: boolean;
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class KeyRmCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Remove an SSH key from balenaCloud.
|
||||||
|
|
||||||
|
Remove a single SSH key registered in balenaCloud for the logged in user.
|
||||||
|
|
||||||
|
The --yes option may be used to avoid interactive confirmation.
|
||||||
|
`;
|
||||||
|
|
||||||
|
public static examples = ['$ balena key rm 17', '$ balena key rm 17 --yes'];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
description: 'balenaCloud ID for the SSH key',
|
||||||
|
parse: x => parseAsInteger(x, 'id'),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'key rm <id>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
yes: cf.yes,
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||||
|
KeyRmCmd,
|
||||||
|
);
|
||||||
|
|
||||||
|
const patterns = await import('../../utils/patterns');
|
||||||
|
|
||||||
|
await patterns.confirm(
|
||||||
|
options.yes ?? false,
|
||||||
|
`Are you sure you want to delete key ${params.id}?`,
|
||||||
|
);
|
||||||
|
|
||||||
|
await getBalenaSdk().models.key.remove(params.id);
|
||||||
|
}
|
||||||
|
}
|
56
lib/actions-oclif/keys.ts
Normal file
56
lib/actions-oclif/keys.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2016-2020 Balena Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { flags } from '@oclif/command';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../command';
|
||||||
|
import * as cf from '../utils/common-flags';
|
||||||
|
import { getBalenaSdk, getVisuals } from '../utils/lazy';
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class KeysCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
List the SSH keys in balenaCloud.
|
||||||
|
|
||||||
|
List all SSH keys registered in balenaCloud for the logged in user.
|
||||||
|
`;
|
||||||
|
public static examples = ['$ balena keys'];
|
||||||
|
|
||||||
|
public static usage = 'keys';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
this.parse<FlagsDef, {}>(KeysCmd);
|
||||||
|
|
||||||
|
const keys = await getBalenaSdk().models.key.getAll();
|
||||||
|
|
||||||
|
// Use 'name' instead of 'title' to match dashboard.
|
||||||
|
const displayKeys: Array<{ id: number; name: string }> = keys.map(k => {
|
||||||
|
return { id: k.id, name: k.title };
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(getVisuals().table.horizontal(displayKeys, ['id', 'name']));
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,6 @@ module.exports =
|
|||||||
auth: require('./auth')
|
auth: require('./auth')
|
||||||
device: require('./device')
|
device: require('./device')
|
||||||
tags: require('./tags')
|
tags: require('./tags')
|
||||||
keys: require('./keys')
|
|
||||||
logs: require('./logs')
|
logs: require('./logs')
|
||||||
local: require('./local')
|
local: require('./local')
|
||||||
scan: require('./scan')
|
scan: require('./scan')
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2016-2020 Balena Ltd.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { CommandDefinition } from 'capitano';
|
|
||||||
import { ExpectedError } from '../errors';
|
|
||||||
import { getBalenaSdk, getVisuals } from '../utils/lazy';
|
|
||||||
import * as commandOptions from './command-options';
|
|
||||||
|
|
||||||
function parseId(id: string): number {
|
|
||||||
if (/^[\d]+$/.exec(id) == null) {
|
|
||||||
throw new ExpectedError('The key id must be an integer');
|
|
||||||
}
|
|
||||||
return Number(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const list: CommandDefinition = {
|
|
||||||
signature: 'keys',
|
|
||||||
description: 'list all ssh keys',
|
|
||||||
help: `\
|
|
||||||
Use this command to list all your SSH keys.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena keys\
|
|
||||||
`,
|
|
||||||
permission: 'user',
|
|
||||||
async action() {
|
|
||||||
const keys = await getBalenaSdk().models.key.getAll();
|
|
||||||
|
|
||||||
console.log(getVisuals().table.horizontal(keys, ['id', 'title']));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const info: CommandDefinition<{ id: string }> = {
|
|
||||||
signature: 'key <id>',
|
|
||||||
description: 'list a single ssh key',
|
|
||||||
help: `\
|
|
||||||
Use this command to show information about a single SSH key.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena key 17\
|
|
||||||
`,
|
|
||||||
permission: 'user',
|
|
||||||
async action(params) {
|
|
||||||
const key = await getBalenaSdk().models.key.get(parseId(params.id));
|
|
||||||
|
|
||||||
console.log(getVisuals().table.vertical(key, ['id', 'title']));
|
|
||||||
|
|
||||||
// Since the public key string is long, it might
|
|
||||||
// wrap to lines below, causing the table layout to break.
|
|
||||||
// See https://github.com/balena-io/balena-cli/issues/151
|
|
||||||
console.log('\n' + key.public_key);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const remove: CommandDefinition<
|
|
||||||
{ id: string },
|
|
||||||
commandOptions.YesOption
|
|
||||||
> = {
|
|
||||||
signature: 'key rm <id>',
|
|
||||||
description: 'remove a ssh key',
|
|
||||||
help: `\
|
|
||||||
Use this command to remove a SSH key from balena.
|
|
||||||
|
|
||||||
Notice this command asks for confirmation interactively.
|
|
||||||
You can avoid this by passing the \`--yes\` boolean option.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena key rm 17
|
|
||||||
$ balena key rm 17 --yes\
|
|
||||||
`,
|
|
||||||
options: [commandOptions.yes],
|
|
||||||
permission: 'user',
|
|
||||||
async action(params, options) {
|
|
||||||
const patterns = await import('../utils/patterns');
|
|
||||||
|
|
||||||
await patterns.confirm(
|
|
||||||
options.yes ?? false,
|
|
||||||
'Are you sure you want to delete the key?',
|
|
||||||
);
|
|
||||||
|
|
||||||
await getBalenaSdk().models.key.remove(parseId(params.id));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const add: CommandDefinition<{ name: string; path: string }> = {
|
|
||||||
signature: 'key add <name> [path]',
|
|
||||||
description: 'add a SSH key to balena',
|
|
||||||
help: `\
|
|
||||||
Use this command to associate a new SSH key with your account.
|
|
||||||
|
|
||||||
If \`path\` is omitted, the command will attempt
|
|
||||||
to read the SSH key from stdin.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena key add Main ~/.ssh/id_rsa.pub
|
|
||||||
$ cat ~/.ssh/id_rsa.pub | balena key add Main\
|
|
||||||
`,
|
|
||||||
permission: 'user',
|
|
||||||
async action(params) {
|
|
||||||
let key: string;
|
|
||||||
if (params.path != null) {
|
|
||||||
const { promisify } = await import('util');
|
|
||||||
const readFileAsync = promisify((await import('fs')).readFile);
|
|
||||||
key = await readFileAsync(params.path, 'utf8');
|
|
||||||
} else {
|
|
||||||
const getStdin = await import('get-stdin');
|
|
||||||
key = await getStdin();
|
|
||||||
}
|
|
||||||
|
|
||||||
await getBalenaSdk().models.key.create(params.name, key);
|
|
||||||
},
|
|
||||||
};
|
|
@ -74,12 +74,6 @@ capitano.command(actions.device.move)
|
|||||||
capitano.command(actions.device.osUpdate)
|
capitano.command(actions.device.osUpdate)
|
||||||
capitano.command(actions.device.info)
|
capitano.command(actions.device.info)
|
||||||
|
|
||||||
# ---------- Keys Module ----------
|
|
||||||
capitano.command(actions.keys.list)
|
|
||||||
capitano.command(actions.keys.add)
|
|
||||||
capitano.command(actions.keys.info)
|
|
||||||
capitano.command(actions.keys.remove)
|
|
||||||
|
|
||||||
# ---------- Tags Module ----------
|
# ---------- Tags Module ----------
|
||||||
capitano.command(actions.tags.list)
|
capitano.command(actions.tags.list)
|
||||||
capitano.command(actions.tags.set)
|
capitano.command(actions.tags.set)
|
||||||
|
@ -134,6 +134,10 @@ export const convertedCommands = [
|
|||||||
'internal:scandevices',
|
'internal:scandevices',
|
||||||
'internal:osinit',
|
'internal:osinit',
|
||||||
'join',
|
'join',
|
||||||
|
'keys',
|
||||||
|
'key',
|
||||||
|
'key:add',
|
||||||
|
'key:rm',
|
||||||
'leave',
|
'leave',
|
||||||
'note',
|
'note',
|
||||||
'os:configure',
|
'os:configure',
|
||||||
|
@ -46,3 +46,8 @@ export const verbose: IBooleanFlag<boolean> = flags.boolean({
|
|||||||
char: 'v',
|
char: 'v',
|
||||||
description: 'produce verbose output',
|
description: 'produce verbose output',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const yes: IBooleanFlag<boolean> = flags.boolean({
|
||||||
|
char: 'y',
|
||||||
|
description: 'answer "yes" to all questions (non interactive use)',
|
||||||
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2016-2017 Balena
|
Copyright 2016-2020 Balena Ltd.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -15,6 +15,7 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import validEmail = require('@resin.io/valid-email');
|
import validEmail = require('@resin.io/valid-email');
|
||||||
|
import { ExpectedError } from '../errors';
|
||||||
|
|
||||||
const APPNAME_REGEX = new RegExp(/^[a-zA-Z0-9_-]+$/);
|
const APPNAME_REGEX = new RegExp(/^[a-zA-Z0-9_-]+$/);
|
||||||
// An regex to detect an IP address, from https://www.regular-expressions.info/ip.html
|
// An regex to detect an IP address, from https://www.regular-expressions.info/ip.html
|
||||||
@ -73,3 +74,17 @@ export function validateShortUuid(input: string): boolean {
|
|||||||
export function validateUuid(input: string): boolean {
|
export function validateUuid(input: string): boolean {
|
||||||
return validateLongUuid(input) || validateShortUuid(input);
|
return validateLongUuid(input) || validateShortUuid(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseAsInteger(input: string, paramName?: string) {
|
||||||
|
// Allow only digits, no leading 0
|
||||||
|
if (!/^(0|[1-9][0-9]*)$/.test(input)) {
|
||||||
|
const message =
|
||||||
|
paramName == null
|
||||||
|
? 'The parameter must be an integer.'
|
||||||
|
: `The parameter '${paramName}' must be an integer.`;
|
||||||
|
|
||||||
|
throw new ExpectedError(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Number(input);
|
||||||
|
}
|
||||||
|
@ -61,10 +61,10 @@ Additional commands:
|
|||||||
env rename <id> <value> change the value of a config or env var for an app, device or service
|
env rename <id> <value> change the value of a config or env var for an app, device or service
|
||||||
env rm <id> remove a config or env var from an application, device or service
|
env rm <id> remove a config or env var from an application, device or service
|
||||||
envs list the environment or config variables of an application, device or service
|
envs list the environment or config variables of an application, device or service
|
||||||
key <id> list a single ssh key
|
key <id> display an SSH key
|
||||||
key add <name> [path] add a SSH key to balena
|
key add <name> [path] add an SSH key to balenaCloud
|
||||||
key rm <id> remove a ssh key
|
key rm <id> remove an SSH key from balenaCloud
|
||||||
keys list all ssh keys
|
keys list the SSH keys in balenaCloud
|
||||||
local configure <target> (Re)configure a balenaOS drive or image
|
local configure <target> (Re)configure a balenaOS drive or image
|
||||||
local flash <image> Flash an image to a drive
|
local flash <image> Flash an image to a drive
|
||||||
logout logout from balena
|
logout logout from balena
|
||||||
|
54
tests/utils/validation.spec.ts
Normal file
54
tests/utils/validation.spec.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2020 Balena Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { ExpectedError } from '../../build/errors';
|
||||||
|
import { parseAsInteger } from '../../build/utils/validation';
|
||||||
|
|
||||||
|
describe('parseAsInteger() function', function() {
|
||||||
|
it('should reject non-numeric characters', () => {
|
||||||
|
expect(() => parseAsInteger('abc')).to.throw(ExpectedError);
|
||||||
|
expect(() => parseAsInteger('1a')).to.throw(ExpectedError);
|
||||||
|
expect(() => parseAsInteger('a1')).to.throw(ExpectedError);
|
||||||
|
expect(() => parseAsInteger('a')).to.throw(ExpectedError);
|
||||||
|
expect(() => parseAsInteger('1.0')).to.throw(ExpectedError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject leading zeros', () => {
|
||||||
|
expect(() => parseAsInteger('01')).to.throw(ExpectedError);
|
||||||
|
expect(() => parseAsInteger('001')).to.throw(ExpectedError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw with specific message when param name passed', () => {
|
||||||
|
expect(() => parseAsInteger('abc')).to.throw(
|
||||||
|
'The parameter must be an integer.',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw with general message when no param name passed', () => {
|
||||||
|
expect(() => parseAsInteger('abc', 'foo')).to.throw(
|
||||||
|
"The parameter 'foo' must be an integer.",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse integers to number type', () => {
|
||||||
|
expect(parseAsInteger('100')).to.equal(100);
|
||||||
|
expect(parseAsInteger('100')).to.be.a('number');
|
||||||
|
expect(parseAsInteger('0')).to.equal(0);
|
||||||
|
expect(parseAsInteger('0')).to.be.a('number');
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user