mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-06-24 10:35:39 +00:00
Compare commits
182 Commits
Author | SHA1 | Date | |
---|---|---|---|
776115ef5d | |||
f031ec1dea | |||
fe42438090 | |||
b616fbdd79 | |||
81edfbbae1 | |||
663e83c3b8 | |||
b650f8ff6d | |||
58234f17e1 | |||
77905f4a74 | |||
30076fabe6 | |||
28703bb5ae | |||
37b3c6abe9 | |||
b4e473e4d4 | |||
0d4e411777 | |||
7e6f2189e8 | |||
3903daf8a8 | |||
18bc0d61e7 | |||
7f2daeebb0 | |||
813e9cb82e | |||
3bcb3c1b2e | |||
20d76556c2 | |||
e829068725 | |||
650e896f70 | |||
a9042124ea | |||
d24d78dac7 | |||
42c50ef8ae | |||
ba4b9bd447 | |||
02c0ea5b59 | |||
bc3558dd8e | |||
aad62d1ccd | |||
ecc6f80164 | |||
c0fd1e3886 | |||
9d3120b144 | |||
ed0e03ddb2 | |||
8fe6d6c026 | |||
727033ae14 | |||
c19ce6a905 | |||
1a33029738 | |||
043bc48a1c | |||
a10156a441 | |||
4f665f43d2 | |||
9f097a96f5 | |||
64d1943804 | |||
666ce876e6 | |||
e01184080f | |||
93039b010d | |||
795259bf30 | |||
fa134d2d39 | |||
bef5221ed8 | |||
72d6db796c | |||
e848eb63ee | |||
6f0f7350cf | |||
07a88c700e | |||
9cae66bd92 | |||
cddea24cef | |||
b1c246c0b4 | |||
00b4d57a03 | |||
2cba82e914 | |||
1352c5c823 | |||
c86eb97010 | |||
53be743b9d | |||
d9f21b4c3f | |||
261ab398dd | |||
f28a9992e4 | |||
29e7827eb1 | |||
1d77cf3665 | |||
017c767f61 | |||
7d79c4e24b | |||
60bc5092e0 | |||
a33a794931 | |||
f0ede6fca2 | |||
dbe177e766 | |||
09f80730a8 | |||
327d28c103 | |||
56ab785a82 | |||
305d65d5ed | |||
c4d3686a34 | |||
ce06854b55 | |||
8db05cc8a7 | |||
7a22c987d2 | |||
45efbcdfe3 | |||
d6a9b78b3e | |||
e8ac3ea960 | |||
0ffa0f85a2 | |||
5e7479f60e | |||
07365c45f2 | |||
e5076434c6 | |||
5d687f5a55 | |||
e192767156 | |||
5a8d2fad5f | |||
45f482fad1 | |||
c0e7ae9c91 | |||
36077cacda | |||
82b9983450 | |||
703dbd01c9 | |||
602e63c8a9 | |||
2ab635f49a | |||
322736a145 | |||
c347b67b25 | |||
4022beeb56 | |||
ccf97cfc9f | |||
9c5fe14f2e | |||
38e29251e7 | |||
bfc7a14646 | |||
610db81fcb | |||
d1f7d6d07f | |||
694eb78aaa | |||
1caccafbcd | |||
61d4d1f1e7 | |||
a01c85bc15 | |||
5d7b7cfc6f | |||
92fd9e0883 | |||
24273b5ac0 | |||
6155509f4c | |||
735af9f6a9 | |||
d7c60e6dea | |||
bcb42c8a21 | |||
04f5e0fa2b | |||
8cb5804848 | |||
91c3fced49 | |||
99a94eafbb | |||
b4cff78588 | |||
8577bb6281 | |||
e0f081623b | |||
2887ab8200 | |||
aaf4625abb | |||
6f30dc0550 | |||
6565ef4392 | |||
60b46192a2 | |||
bb101de96e | |||
ca6344bf4c | |||
48596fa318 | |||
7fb28ddb21 | |||
6dd6f43d64 | |||
07a7bd76fe | |||
4b3fdcf99c | |||
d023d0af91 | |||
de1821d7ac | |||
12923c9b84 | |||
8be069dbdb | |||
9d3f9128a8 | |||
61ebf9e4fd | |||
84985022e5 | |||
c5d8f73263 | |||
5db0c71bb3 | |||
c7a06f7259 | |||
bc66febc50 | |||
bb80311700 | |||
3dee7bd6f6 | |||
3251f04287 | |||
35dce4579a | |||
71ef00534d | |||
b6f8be27ec | |||
13110cca45 | |||
d4b554da1b | |||
1275c11573 | |||
593233a99f | |||
ec92f21b70 | |||
5adc43bcbd | |||
1ee9a68288 | |||
56e5dafb20 | |||
f0e0c0d728 | |||
afd14794f5 | |||
37e08e4667 | |||
61af57acc9 | |||
19be0fec1a | |||
2b656c23b3 | |||
2bf7b81645 | |||
746b6fa439 | |||
f52e218290 | |||
8655b89313 | |||
09d52c504d | |||
e5cee648f2 | |||
98a6b431d9 | |||
f305d5d9a0 | |||
5cb5ac80a6 | |||
3eb3b3b584 | |||
8ee5ede34d | |||
d6d08cc7c9 | |||
76c63d4b20 | |||
bff5897047 | |||
22c9fd399e |
@ -1,2 +0,0 @@
|
||||
/completion/*
|
||||
/bin/*
|
21
.eslintrc.js
21
.eslintrc.js
@ -1,21 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@balena/lint/config/.eslintrc.js'],
|
||||
parserOptions: {
|
||||
project: 'tsconfig.dev.json',
|
||||
},
|
||||
root: true,
|
||||
rules: {
|
||||
ignoreDefinitionFiles: 0,
|
||||
// to avoid the `warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion`
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-shadow': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: ['resin-cli-visuals', 'chalk', 'common-tags', 'resin-cli-form'],
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
||||
},
|
||||
};
|
6
.github/actions/publish/action.yml
vendored
6
.github/actions/publish/action.yml
vendored
@ -39,7 +39,7 @@ runs:
|
||||
run: tar -xf ${{ runner.temp }}/custom.tgz
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4
|
||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
||||
with:
|
||||
node-version: ${{ inputs.NODE_VERSION }}
|
||||
cache: npm
|
||||
@ -94,7 +94,7 @@ runs:
|
||||
runner_arch="$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
if [[ $runner_os =~ darwin|macos|osx ]]; then
|
||||
CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}
|
||||
CSC_KEY_PASSWORD='${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}'
|
||||
CSC_KEYCHAIN=signing_temp
|
||||
CSC_LINK=${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
|
||||
|
||||
@ -135,7 +135,7 @@ runs:
|
||||
XCODE_APP_LOADER_TEAM_ID: ${{ inputs.XCODE_APP_LOADER_TEAM_ID }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
|
||||
with:
|
||||
name: gh-release-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ strategy.job-index }}
|
||||
path: dist
|
||||
|
4
.github/actions/test/action.yml
vendored
4
.github/actions/test/action.yml
vendored
@ -26,7 +26,7 @@ runs:
|
||||
steps:
|
||||
# https://github.com/actions/setup-node#caching-global-packages-data
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4
|
||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
||||
with:
|
||||
node-version: ${{ inputs.NODE_VERSION }}
|
||||
cache: npm
|
||||
@ -58,7 +58,7 @@ runs:
|
||||
run: tar --exclude-vcs -acf ${{ runner.temp }}/custom.tgz .
|
||||
|
||||
- name: Upload custom artifact
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
|
||||
with:
|
||||
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}-${{ runner.arch }}
|
||||
path: ${{ runner.temp }}/custom.tgz
|
||||
|
4
.github/workflows/flowzone.yml
vendored
4
.github/workflows/flowzone.yml
vendored
@ -26,7 +26,7 @@ jobs:
|
||||
"os": [
|
||||
["self-hosted", "X64"],
|
||||
["self-hosted", "ARM64"],
|
||||
["macos-12"],
|
||||
["macos-13"],
|
||||
["windows-2019"],
|
||||
["macos-latest-xlarge"]
|
||||
]
|
||||
@ -36,7 +36,7 @@ jobs:
|
||||
"os": [
|
||||
["self-hosted", "X64"],
|
||||
["self-hosted", "ARM64"],
|
||||
["macos-12"],
|
||||
["macos-13"],
|
||||
["windows-2019"],
|
||||
["macos-latest-xlarge"]
|
||||
]
|
||||
|
File diff suppressed because it is too large
Load Diff
328
CHANGELOG.md
328
CHANGELOG.md
@ -4,6 +4,334 @@ All notable changes to this project will be documented in this file
|
||||
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 21.1.6 - 2025-04-03
|
||||
|
||||
* Update actions/setup-node digest to cdca736 [balena-renovate[bot]]
|
||||
|
||||
## 21.1.5 - 2025-04-03
|
||||
|
||||
* Update dockerode/docker-modem dependencies for fixes [Ken Bannister]
|
||||
|
||||
## 21.1.4 - 2025-04-02
|
||||
|
||||
* Add comment with secure boot signature file example for preload [Ken Bannister]
|
||||
|
||||
## 21.1.3 - 2025-03-28
|
||||
|
||||
* Fix device detail for open balena [Otavio Jacobi]
|
||||
|
||||
## 21.1.2 - 2025-03-27
|
||||
|
||||
* Deny preload for an image with secure boot enabled [Ken Bannister]
|
||||
|
||||
## 21.1.1 - 2025-03-26
|
||||
|
||||
|
||||
<details>
|
||||
<summary> Bump balena-sdk to 21.3.0 [Otavio Jacobi] </summary>
|
||||
|
||||
> ### balena-sdk-21.3.0 - 2025-03-26
|
||||
>
|
||||
> * device: add `changed_api_heartbeat_state_on__date` to typings [Otavio Jacobi]
|
||||
>
|
||||
> ### balena-sdk-21.2.2 - 2025-03-26
|
||||
>
|
||||
> * fix linting [Otavio Jacobi]
|
||||
>
|
||||
|
||||
</details>
|
||||
|
||||
## 21.1.0 - 2025-03-12
|
||||
|
||||
* Add support for new requirement labels feature [Felipe Lalanne]
|
||||
|
||||
## 21.0.0 - 2025-03-11
|
||||
|
||||
* Drop support for OS versions <2.14.0 [myarmolinsky]
|
||||
* api-key generate: Add required argument `expiryDate` [myarmolinsky]
|
||||
* Update `balena-preload` to 18.0.1 [myarmolinsky]
|
||||
* Add dependency `date-fns` [myarmolinsky]
|
||||
* Update `balena-sdk` to 21.2.1 [myarmolinsky]
|
||||
|
||||
## 20.2.10 - 2025-03-10
|
||||
|
||||
* Update TypeScript to 5.8.2 [Thodoris Greasidis]
|
||||
|
||||
## 20.2.9 - 2025-02-26
|
||||
|
||||
* Fix CORS issue with X-Balena-Client header [Thodoris Greasidis]
|
||||
|
||||
## 20.2.8 - 2025-02-26
|
||||
|
||||
* Update balena-config-json dependency and fix test [Ken Bannister]
|
||||
|
||||
## 20.2.7 - 2025-02-25
|
||||
|
||||
* Use the CLI version in the X-Balena-Client header [Thodoris Greasidis]
|
||||
|
||||
## 20.2.6 - 2025-02-25
|
||||
|
||||
* Update actions/upload-artifact digest to 4cec3d8 [balena-renovate[bot]]
|
||||
|
||||
## 20.2.5 - 2025-02-25
|
||||
|
||||
* Update actions/setup-node digest to 1d0ff46 [balena-renovate[bot]]
|
||||
|
||||
## 20.2.4 - 2025-02-25
|
||||
|
||||
* Pin docker-modem and dockerode to avoid regression [Ken Bannister]
|
||||
|
||||
## 20.2.3 - 2025-01-15
|
||||
|
||||
* Remove unused old eslint version files [Otavio Jacobi]
|
||||
|
||||
## 20.2.2 - 2025-01-12
|
||||
|
||||
* Use the promises namespace of balena-image-fs [Thodoris Greasidis]
|
||||
|
||||
<details>
|
||||
<summary> Update balena-device-init to 8.1.3 & balena-image-fs to 7.3.0 [Thodoris Greasidis] </summary>
|
||||
|
||||
> ### balena-image-fs-7.3.0 - 2025-01-06
|
||||
>
|
||||
> * Drop Bluebird from devDependencies [Thodoris Greasidis]
|
||||
> * flowzone: Remove empty with clause [Thodoris Greasidis]
|
||||
> * Add the promises namespace as part of the exposed fs [Thodoris Greasidis]
|
||||
>
|
||||
> ### balena-image-fs-7.2.2 - 2024-01-02
|
||||
>
|
||||
> * Update dependency @types/node to v20 [Self-hosted Renovate Bot]
|
||||
>
|
||||
> ### balena-image-fs-7.2.1 - 2023-12-19
|
||||
>
|
||||
> * Remove repo config from flowzone.yml [Kyle Harding]
|
||||
>
|
||||
> ### balena-image-fs-7.2.0 - 2023-01-20
|
||||
>
|
||||
> * Add support for Node 18 [Akis Kesoglou]
|
||||
>
|
||||
> ### balena-image-fs-7.1.2 - 2023-01-05
|
||||
>
|
||||
> * Update dependencies [ab77]
|
||||
>
|
||||
> ### balena-image-fs-7.1.1 - 2022-12-20
|
||||
>
|
||||
> * Update dependency jsdoc-to-markdown to 8.0.0 [Renovate Bot]
|
||||
>
|
||||
> ### balena-image-fs-7.1.0 - 2022-12-13
|
||||
>
|
||||
> * update dependencies [Zane Hitchcox]
|
||||
>
|
||||
> ### balena-device-init-8.1.3 - 2025-01-09
|
||||
>
|
||||
> * README: Remove the travisci badge [Thodoris Greasidis]
|
||||
>
|
||||
> ### balena-device-init-8.1.2 - 2025-01-09
|
||||
>
|
||||
>
|
||||
> <details>
|
||||
> <summary> Use the promises namespace of balena-image-fs [Thodoris Greasidis] </summary>
|
||||
>
|
||||
>> #### balena-image-fs-7.3.0 - 2025-01-06
|
||||
>>
|
||||
>> * Drop Bluebird from devDependencies [Thodoris Greasidis]
|
||||
>> * flowzone: Remove empty with clause [Thodoris Greasidis]
|
||||
>> * Add the promises namespace as part of the exposed fs [Thodoris Greasidis]
|
||||
>>
|
||||
>> #### balena-image-fs-7.2.2 - 2024-01-02
|
||||
>>
|
||||
>> * Update dependency @types/node to v20 [Self-hosted Renovate Bot]
|
||||
>>
|
||||
>> #### balena-image-fs-7.2.1 - 2023-12-19
|
||||
>>
|
||||
>> * Remove repo config from flowzone.yml [Kyle Harding]
|
||||
>>
|
||||
>> #### balena-image-fs-7.2.0 - 2023-01-20
|
||||
>>
|
||||
>> * Add support for Node 18 [Akis Kesoglou]
|
||||
>>
|
||||
>> #### balena-image-fs-7.1.2 - 2023-01-05
|
||||
>>
|
||||
>> * Update dependencies [ab77]
|
||||
>>
|
||||
>> #### balena-image-fs-7.1.1 - 2022-12-20
|
||||
>>
|
||||
>> * Update dependency jsdoc-to-markdown to 8.0.0 [Renovate Bot]
|
||||
>>
|
||||
>> #### balena-image-fs-7.1.0 - 2022-12-13
|
||||
>>
|
||||
>> * update dependencies [Zane Hitchcox]
|
||||
>>
|
||||
>
|
||||
> </details>
|
||||
>
|
||||
>
|
||||
> ### balena-device-init-8.1.1 - 2025-01-06
|
||||
>
|
||||
> * Convert some parts to async await and simplify [Thodoris Greasidis]
|
||||
> * Avoid unnecessary destructuring [Thodoris Greasidis]
|
||||
>
|
||||
|
||||
</details>
|
||||
|
||||
## 20.2.1 - 2025-01-01
|
||||
|
||||
|
||||
<details>
|
||||
<summary> Update balena-preload to 17.0.0 [Thodoris Greasidis] </summary>
|
||||
|
||||
> ### balena-preload-17.0.0 - 2024-10-21
|
||||
>
|
||||
> * Improve typings [Thodoris Greasidis]
|
||||
> * Stop returning Bluebird promises & drop it from the dependencies [Thodoris Greasidis]
|
||||
>
|
||||
|
||||
</details>
|
||||
|
||||
## 20.2.0 - 2024-12-31
|
||||
|
||||
|
||||
<details>
|
||||
<summary> os configure: Give precedence to the boot partition located in the image over the device-type.json contents [Thodoris Greasidis] </summary>
|
||||
|
||||
> ### balena-device-init-8.1.0 - Invalid date
|
||||
>
|
||||
> * Try to find the boot partition by inspecting the image [Thodoris Greasidis]
|
||||
>
|
||||
> ### balena-device-init-8.0.1 - 2024-12-19
|
||||
>
|
||||
> * Drop the unnecessary eslint.config.js [Thodoris Greasidis]
|
||||
> * packacke.json: Explicitly set type commonjs [Thodoris Greasidis]
|
||||
>
|
||||
|
||||
</details>
|
||||
|
||||
## 20.1.6 - 2024-12-30
|
||||
|
||||
* Add more realistic os configure tests [Thodoris Greasidis]
|
||||
|
||||
## 20.1.5 - 2024-12-20
|
||||
|
||||
* Update shrinkwrapped express to v4.21.2 [Oskar Williams]
|
||||
|
||||
## 20.1.4 - 2024-12-20
|
||||
|
||||
|
||||
<details>
|
||||
<summary> Update balena-device-init to 8.0.0 [Thodoris Greasidis] </summary>
|
||||
|
||||
> ### balena-device-init-8.0.0 - 2024-12-18
|
||||
>
|
||||
> * Avoid running linting in the custom tests [Thodoris Greasidis]
|
||||
> * Stop returning Bluebird promises [Thodoris Greasidis]
|
||||
> * package: Publish only the build & typings folders [Thodoris Greasidis]
|
||||
> * Convert to TypeScript with es6 module notation [Thodoris Greasidis]
|
||||
> * Replace gulp, coffeelint & mochainon with tsc, @balena/lint, mocha, chai & sinon [Thodoris Greasidis]
|
||||
> * Drop support for node <20.6.0 [Thodoris Greasidis]
|
||||
>
|
||||
> ### balena-device-init-7.0.2 - 2024-12-17
|
||||
>
|
||||
> * flowzone: Update runner versions [Thodoris Greasidis]
|
||||
> * Pin etcher-sdk to 9.0.8 to match resin-device-operations and fix tests [Thodoris Greasidis]
|
||||
>
|
||||
|
||||
</details>
|
||||
|
||||
## 20.1.3 - 2024-12-20
|
||||
|
||||
* Update oclif to 4.17.0 and @oclif/core 4.1.0 [Otavio Jacobi]
|
||||
|
||||
## 20.1.2 - 2024-12-17
|
||||
|
||||
* Remove unnecessary `Promise.resolve` and `Promise.reject` [Pagan Gazzard]
|
||||
|
||||
## 20.1.1 - 2024-12-16
|
||||
|
||||
* Update @balena/lint to v9.1.3 [Otavio Jacobi]
|
||||
|
||||
## 20.1.0 - 2024-12-12
|
||||
|
||||
* `device os-update`: Add handling for updates that require takeover [myarmolinsky]
|
||||
* Update `balena-sdk` [myarmolinsky]
|
||||
* Update `@balena/compose` [myarmolinsky]
|
||||
|
||||
## 20.0.9 - 2024-12-05
|
||||
|
||||
* Update shrinkwrapped express to v4.21.1 [Oskar Williams]
|
||||
|
||||
## 20.0.8 - 2024-12-04
|
||||
|
||||
* Run test and publish with macos-13 [Otavio Jacobi]
|
||||
|
||||
## 20.0.7 - 2024-11-23
|
||||
|
||||
* Update TypeScript to 5.7.2 [Thodoris Greasidis]
|
||||
|
||||
## 20.0.6 - 2024-11-08
|
||||
|
||||
* Refactor balena build for clarity [Thodoris Greasidis]
|
||||
|
||||
## 20.0.5 - 2024-11-05
|
||||
|
||||
* Update actions/upload-artifact digest to b4b15b8 [balena-renovate[bot]]
|
||||
|
||||
## 20.0.4 - 2024-11-05
|
||||
|
||||
* Update actions/setup-node digest to 39370e3 [balena-renovate[bot]]
|
||||
|
||||
## 20.0.3 - 2024-11-05
|
||||
|
||||
* api-key generate: Display a descriptive error when the generation fails due to a stale JWT [Thodoris Greasidis]
|
||||
|
||||
## 20.0.2 - 2024-10-29
|
||||
|
||||
* Restore ability to cat key into `ssh-key add` [myarmolinsky]
|
||||
|
||||
## 20.0.1 - 2024-10-29
|
||||
|
||||
* Fix sending input to some aliases not working [myarmolinsky]
|
||||
|
||||
## 20.0.0 - 2024-10-25
|
||||
|
||||
* `device update`: Use detached HUP for os updates [jaomaloy]
|
||||
* Drop `-h` flag for help and stop manually adding `help` per command in favor of oclif automatically adding it [myarmolinsky]
|
||||
* Stop checking for very old, long-removed commands [myarmolinsky]
|
||||
* Deprecate `devices supported` command in favor of `device-type list` [myarmolinsky]
|
||||
* Deprecate `notes` command in favor of `device note` [myarmolinsky]
|
||||
* Deprecate `tunnel` command in favor of `device tunnel` [myarmolinsky]
|
||||
* Deprecate `env add` in favor of `env set` [myarmolinsky]
|
||||
* Deprecate `ssh` command in favor of `device ssh` [myarmolinsky]
|
||||
* Deprecate `logs` command in favor of `device logs` [myarmolinsky]
|
||||
* Deprecate `scan` command in favor of `device detect` [myarmolinsky]
|
||||
* Deprecate `orgs` command in favor of `organization list` [myarmolinsky]
|
||||
* Deprecate `tags` command in favor of `tag list` [myarmolinsky]
|
||||
* Deprecate `envs` command in favor of `env list` [myarmolinsky]
|
||||
* Deprecate `key` commands in favor of `ssh-key` [myarmolinsky]
|
||||
* Deprecate `keys` command in favor of `key list` [myarmolinsky]
|
||||
* Deprecate `releases` command in favor of `release list` [myarmolinsky]
|
||||
* Deprecate `fleets` command in favor of `fleet list` [myarmolinsky]
|
||||
* Deprecate `api-keys` command in favor of `api-key list` [myarmolinsky]
|
||||
* Deprecate `devices` command in favor of `device list` [myarmolinsky]
|
||||
* Docs: Show whether an alias is deprecated [myarmolinsky]
|
||||
* Update `balena-preload` to 16.0.0 [myarmolinsky]
|
||||
* Tests: Drop unused `my_application` resource mock [myarmolinsky]
|
||||
* Rename `device.overall_status` values: `IDLE` to `OPERATIONAL`, `OFFLINE` to `DISCONNECTED`; add `REDUCED_FUNCTIONALITY` [myarmolinsky]
|
||||
* Update `@balena/compose` to 5.0.0 [myarmolinsky]
|
||||
* Bump balena-sdk to 20.3.0 [myarmolinsky]
|
||||
|
||||
## 19.16.0 - 2024-10-23
|
||||
|
||||
* device-type list: Add `--all` flag for including no longer supported device types in the list [myarmolinsky]
|
||||
* Add alias `device-type list` for command `devices supported` [myarmolinsky]
|
||||
|
||||
## 19.15.0 - 2024-10-23
|
||||
|
||||
* Add alias `device note` for command `notes` [myarmolinsky]
|
||||
|
||||
## 19.14.0 - 2024-10-22
|
||||
|
||||
* Add alias `device tunnel` for command `tunnel` [myarmolinsky]
|
||||
|
||||
## 19.13.1 - 2024-10-21
|
||||
|
||||
* Update dependency chalk to v4 [Self-hosted Renovate Bot]
|
||||
|
@ -31,7 +31,7 @@ command again.
|
||||
|
||||
Check whether the SD card is locked (a physical switch on the side of the card).
|
||||
|
||||
## I get `connect ETIMEDOUT` with `balena tunnel`
|
||||
## I get `connect ETIMEDOUT` with `balena device tunnel`
|
||||
|
||||
Please update the CLI to the latest version. This issue was fixed in v12.38.5.
|
||||
For more details, see: https://github.com/balena-io/balena-cli/issues/2172
|
||||
|
@ -305,7 +305,7 @@ async function zipPkg() {
|
||||
);
|
||||
}
|
||||
await fs.mkdirp(path.dirname(outputFile));
|
||||
await new Promise((resolve, reject) => {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
console.log(`Zipping standalone package to "${outputFile}"...`);
|
||||
|
||||
const archive = archiver('zip', {
|
||||
|
@ -61,7 +61,6 @@ const commandHeadings: { [key: string]: string } = {
|
||||
organization: 'Organizations',
|
||||
os: 'OS',
|
||||
util: 'Utilities',
|
||||
tunnel: 'Network',
|
||||
build: 'Deploy',
|
||||
join: 'Platform',
|
||||
leave: 'Platform',
|
||||
@ -146,7 +145,7 @@ export async function getCapitanoDoc(): Promise<typeof capitanoDoc> {
|
||||
throw new Error(`Error parsing section title`);
|
||||
}
|
||||
// match[1] has the title, match[2] has the rest
|
||||
return match && match[2];
|
||||
return match?.[2];
|
||||
}),
|
||||
mdParser.getSectionOfTitle('Installation'),
|
||||
mdParser.getSectionOfTitle('Choosing a shell (command prompt/terminal)'),
|
||||
|
@ -25,7 +25,14 @@ function renderOclifCommand(command: Category['commands'][0]): string[] {
|
||||
const result = [`## ${ent.encode(command.name || '')}`];
|
||||
if (command.aliases?.length) {
|
||||
result.push('### Aliases');
|
||||
result.push(command.aliases.map((alias) => `- \`${alias}\``).join('\n'));
|
||||
result.push(
|
||||
command.aliases
|
||||
.map(
|
||||
(alias) =>
|
||||
`- \`${alias}\`${command.deprecateAliases ? ' *(deprecated)*' : ''}`,
|
||||
)
|
||||
.join('\n'),
|
||||
);
|
||||
result.push(
|
||||
`\nTo use one of the aliases, replace \`${command.name}\` with the alias.`,
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ import * as semver from 'semver';
|
||||
|
||||
const changeTypes = ['major', 'minor', 'patch'] as const;
|
||||
|
||||
const validateChangeType = (maybeChangeType: string = 'minor') => {
|
||||
const validateChangeType = (maybeChangeType = 'minor') => {
|
||||
maybeChangeType = maybeChangeType.toLowerCase();
|
||||
switch (maybeChangeType) {
|
||||
case 'patch':
|
||||
@ -136,5 +136,4 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
main();
|
||||
void main();
|
||||
|
@ -19,6 +19,7 @@ import { spawn } from 'child_process';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { diffTrimmedLines } from 'diff';
|
||||
import * as whichMod from 'which';
|
||||
|
||||
export const ROOT = path.join(__dirname, '..');
|
||||
|
||||
@ -101,7 +102,6 @@ export function loadPackageJson() {
|
||||
* @returns The program's full path, e.g. 'C:\WINDOWS\System32\OpenSSH\ssh.EXE'
|
||||
*/
|
||||
export async function which(program: string): Promise<string> {
|
||||
const whichMod = await import('which');
|
||||
let programPath: string;
|
||||
try {
|
||||
programPath = await whichMod(program);
|
||||
@ -132,7 +132,7 @@ export async function whichSpawn(
|
||||
.on('error', reject)
|
||||
.on('close', resolve);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
reject(err as Error);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
|
@ -57,7 +57,10 @@ require('ts-node').register({
|
||||
project: path.join(rootDir, 'tsconfig.json'),
|
||||
transpileOnly: true,
|
||||
});
|
||||
require('../src/app').run(undefined, { dir: __dirname, development: true });
|
||||
void require('../src/app').run(undefined, {
|
||||
dir: __dirname,
|
||||
development: true,
|
||||
});
|
||||
|
||||
// Modify package.json oclif paths from build/ -> src/, or vice versa
|
||||
function modifyOclifPaths(revert) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
process.env.UV_THREADPOOL_SIZE = '64';
|
||||
|
||||
// Disable oclif registering ts-node
|
||||
process.env.OCLIF_TS_NODE = 0;
|
||||
process.env.OCLIF_TS_NODE = '0';
|
||||
|
||||
async function run() {
|
||||
// Use fast-boot to cache require lookups, speeding up startup
|
||||
@ -18,4 +18,4 @@ async function run() {
|
||||
await require('../build/app').run(undefined, { dir: __dirname });
|
||||
}
|
||||
|
||||
run();
|
||||
void run();
|
||||
|
@ -8,14 +8,14 @@ _balena() {
|
||||
local context state line curcontext="$curcontext"
|
||||
|
||||
# Valid top-level completions
|
||||
main_commands=( api-key app block build config deploy device devices env fleet internal join leave local login logout notes organization os preload push release settings ssh-key support tag tunnel util version whoami )
|
||||
main_commands=( api-key app block build config deploy device device-type env fleet internal join leave local login logout organization os preload push release settings ssh-key support tag util version whoami )
|
||||
# Sub-completions
|
||||
api_key_cmds=( generate list revoke )
|
||||
app_cmds=( create )
|
||||
block_cmds=( create )
|
||||
config_cmds=( generate inject read reconfigure write )
|
||||
device_cmds=( deactivate detect identify init list local-mode logs move os-update pin public-url purge reboot register rename restart rm shutdown ssh start-service stop-service track-fleet )
|
||||
devices_cmds=( supported )
|
||||
device_type_cmds=( list )
|
||||
device_cmds=( deactivate detect identify init list local-mode logs move note os-update pin public-url purge reboot register rename restart rm shutdown ssh start-service stop-service track-fleet tunnel )
|
||||
env_cmds=( list rename rm set )
|
||||
fleet_cmds=( create list pin purge rename restart rm track-latest )
|
||||
internal_cmds=( osinit )
|
||||
@ -29,7 +29,7 @@ _balena() {
|
||||
|
||||
_arguments -C \
|
||||
'(- 1 *)--version[show version and exit]' \
|
||||
'(- 1 *)'{-h,--help}'[show help options and exit]' \
|
||||
'(- 1 *)--help[show help options and exit]' \
|
||||
'1:first command:_balena_main_cmds' \
|
||||
'2:second command:_balena_sec_cmds' \
|
||||
&& ret=0
|
||||
@ -55,12 +55,12 @@ _balena_sec_cmds() {
|
||||
"config")
|
||||
_describe -t config_cmds 'config_cmd' config_cmds "$@" && ret=0
|
||||
;;
|
||||
"device-type")
|
||||
_describe -t device_type_cmds 'device-type_cmd' device_type_cmds "$@" && ret=0
|
||||
;;
|
||||
"device")
|
||||
_describe -t device_cmds 'device_cmd' device_cmds "$@" && ret=0
|
||||
;;
|
||||
"devices")
|
||||
_describe -t devices_cmds 'devices_cmd' devices_cmds "$@" && ret=0
|
||||
;;
|
||||
"env")
|
||||
_describe -t env_cmds 'env_cmd' env_cmds "$@" && ret=0
|
||||
;;
|
||||
|
@ -7,14 +7,14 @@ _balena_complete()
|
||||
local cur prev
|
||||
|
||||
# Valid top-level completions
|
||||
main_commands="api-key app block build config deploy device devices env fleet internal join leave local login logout notes organization os preload push release settings ssh-key support tag tunnel util version whoami"
|
||||
main_commands="api-key app block build config deploy device device-type env fleet internal join leave local login logout organization os preload push release settings ssh-key support tag util version whoami"
|
||||
# Sub-completions
|
||||
api_key_cmds="generate list revoke"
|
||||
app_cmds="create"
|
||||
block_cmds="create"
|
||||
config_cmds="generate inject read reconfigure write"
|
||||
device_cmds="deactivate detect identify init list local-mode logs move os-update pin public-url purge reboot register rename restart rm shutdown ssh start-service stop-service track-fleet"
|
||||
devices_cmds="supported"
|
||||
device_type_cmds="list"
|
||||
device_cmds="deactivate detect identify init list local-mode logs move note os-update pin public-url purge reboot register rename restart rm shutdown ssh start-service stop-service track-fleet tunnel"
|
||||
env_cmds="list rename rm set"
|
||||
fleet_cmds="create list pin purge rename restart rm track-latest"
|
||||
internal_cmds="osinit"
|
||||
@ -49,12 +49,12 @@ _balena_complete()
|
||||
config)
|
||||
COMPREPLY=( $(compgen -W "$config_cmds" -- $cur) )
|
||||
;;
|
||||
device-type)
|
||||
COMPREPLY=( $(compgen -W "$device_type_cmds" -- $cur) )
|
||||
;;
|
||||
device)
|
||||
COMPREPLY=( $(compgen -W "$device_cmds" -- $cur) )
|
||||
;;
|
||||
devices)
|
||||
COMPREPLY=( $(compgen -W "$devices_cmds" -- $cur) )
|
||||
;;
|
||||
env)
|
||||
COMPREPLY=( $(compgen -W "$env_cmds" -- $cur) )
|
||||
;;
|
||||
|
@ -14,7 +14,7 @@ $sub_cmds$
|
||||
|
||||
_arguments -C \
|
||||
'(- 1 *)--version[show version and exit]' \
|
||||
'(- 1 *)'{-h,--help}'[show help options and exit]' \
|
||||
'(- 1 *)--help[show help options and exit]' \
|
||||
'1:first command:_balena_main_cmds' \
|
||||
'2:second command:_balena_sec_cmds' \
|
||||
&& ret=0
|
||||
|
@ -193,6 +193,10 @@ are encouraged to regularly update the balena CLI to the latest version.
|
||||
- [build](#build)
|
||||
- [deploy](#deploy)
|
||||
|
||||
- Device-type
|
||||
|
||||
- [device-type list](#device-type-list)
|
||||
|
||||
- Devices
|
||||
|
||||
- [device deactivate](#device-deactivate)
|
||||
@ -204,6 +208,7 @@ are encouraged to regularly update the balena CLI to the latest version.
|
||||
- [device local-mode](#device-local-mode)
|
||||
- [device logs](#device-logs)
|
||||
- [device move](#device-move)
|
||||
- [device note](#device-note)
|
||||
- [device os-update](#device-os-update)
|
||||
- [device pin](#device-pin)
|
||||
- [device public-url](#device-public-url)
|
||||
@ -218,7 +223,7 @@ are encouraged to regularly update the balena CLI to the latest version.
|
||||
- [device start-service](#device-start-service)
|
||||
- [device stop-service](#device-stop-service)
|
||||
- [device track-fleet](#device-track-fleet)
|
||||
- [devices supported](#devices-supported)
|
||||
- [device tunnel](#device-tunnel)
|
||||
|
||||
- Environment Variables
|
||||
|
||||
@ -244,14 +249,6 @@ are encouraged to regularly update the balena CLI to the latest version.
|
||||
- [local configure](#local-configure)
|
||||
- [local flash](#local-flash)
|
||||
|
||||
- Network
|
||||
|
||||
- [tunnel](#tunnel)
|
||||
|
||||
- Notes
|
||||
|
||||
- [notes](#notes)
|
||||
|
||||
- Organizations
|
||||
|
||||
- [organization list](#organization-list)
|
||||
@ -329,6 +326,8 @@ or to authenticate requests to the API with an 'Authorization: Bearer <key>' hea
|
||||
Examples:
|
||||
|
||||
$ balena api-key generate "Jenkins Key"
|
||||
$ balena api-key generate "Jenkins Key" 2025-10-30
|
||||
$ balena api-key generate "Jenkins Key" never
|
||||
|
||||
### Arguments
|
||||
|
||||
@ -336,13 +335,15 @@ Examples:
|
||||
|
||||
the API key name
|
||||
|
||||
### Options
|
||||
#### EXPIRYDATE
|
||||
|
||||
the expiry date of the API key as an ISO date string, or "never" for no expiry
|
||||
|
||||
## api-key list
|
||||
|
||||
### Aliases
|
||||
|
||||
- `api-keys`
|
||||
- `api-keys` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `api-key list` with the alias.
|
||||
@ -387,8 +388,6 @@ Examples:
|
||||
|
||||
the API key ids
|
||||
|
||||
### Options
|
||||
|
||||
# Apps
|
||||
|
||||
## app create
|
||||
@ -403,7 +402,7 @@ should be provided. Organization handles can be listed with the
|
||||
`balena organization list` command.
|
||||
|
||||
The app's default device type is specified with the `--type` option.
|
||||
The `balena devices supported` command can be used to list the available
|
||||
The `balena device-type list` command can be used to list the available
|
||||
device types.
|
||||
|
||||
Interactive dropdowns will be shown for selection if no device type or
|
||||
@ -432,7 +431,7 @@ handle of the organization the app should belong to
|
||||
|
||||
#### -t, --type TYPE
|
||||
|
||||
app device type (Check available types with `balena devices supported`)
|
||||
app device type (Check available types with `balena device-type list`)
|
||||
|
||||
# Authentication
|
||||
|
||||
@ -533,7 +532,7 @@ should be provided. Organization handles can be listed with the
|
||||
`balena organization list` command.
|
||||
|
||||
The block's default device type is specified with the `--type` option.
|
||||
The `balena devices supported` command can be used to list the available
|
||||
The `balena device-type list` command can be used to list the available
|
||||
device types.
|
||||
|
||||
Interactive dropdowns will be shown for selection if no device type or
|
||||
@ -562,7 +561,7 @@ handle of the organization the block should belong to
|
||||
|
||||
#### -t, --type TYPE
|
||||
|
||||
block device type (Check available types with `balena devices supported`)
|
||||
block device type (Check available types with `balena device-type list`)
|
||||
|
||||
# Config
|
||||
|
||||
@ -644,7 +643,7 @@ custom device key - note that this is only supported on balenaOS 2.0.3+
|
||||
|
||||
#### --deviceType DEVICETYPE
|
||||
|
||||
device type slug (run 'balena devices supported' for possible values)
|
||||
device type slug (run 'balena device-type list' for possible values)
|
||||
|
||||
#### --generate-device-api-key
|
||||
|
||||
@ -1226,6 +1225,47 @@ Docker host TLS certificate file
|
||||
|
||||
Docker host TLS key file
|
||||
|
||||
# Device-type
|
||||
|
||||
## device-type list
|
||||
|
||||
### Aliases
|
||||
|
||||
- `devices supported` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `device-type list` with the alias.
|
||||
|
||||
### Description
|
||||
|
||||
List the device types supported by balena (like 'raspberrypi3' or 'intel-nuc').
|
||||
|
||||
By default, only actively supported device types are listed.
|
||||
The --all option can be used to list all device types, including those that are
|
||||
no longer supported by balena.
|
||||
|
||||
The --json option is recommended when scripting the output of this command,
|
||||
because the JSON format is less likely to change and it better represents data
|
||||
types like lists and empty strings (for example, the ALIASES column contains a
|
||||
list of zero or more values). The 'jq' utility may be helpful in shell scripts
|
||||
(https://stedolan.github.io/jq/manual/).
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena device-type list
|
||||
$ balena device-type list --all
|
||||
$ balena device-type list --json
|
||||
|
||||
### Options
|
||||
|
||||
#### -j, --json
|
||||
|
||||
produce JSON output instead of tabular output
|
||||
|
||||
#### --all
|
||||
|
||||
include device types no longer supported by balena
|
||||
|
||||
# Devices
|
||||
|
||||
## device deactivate
|
||||
@ -1258,7 +1298,7 @@ answer "yes" to all questions (non interactive use)
|
||||
|
||||
### Aliases
|
||||
|
||||
- `scan`
|
||||
- `scan` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `device detect` with the alias.
|
||||
@ -1308,8 +1348,6 @@ Examples:
|
||||
|
||||
the uuid of the device to identify
|
||||
|
||||
### Options
|
||||
|
||||
## device
|
||||
|
||||
### Description
|
||||
@ -1435,7 +1473,7 @@ expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)
|
||||
|
||||
### Aliases
|
||||
|
||||
- `devices`
|
||||
- `devices` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `device list` with the alias.
|
||||
@ -1516,7 +1554,7 @@ output boolean indicating local mode status
|
||||
|
||||
### Aliases
|
||||
|
||||
- `logs`
|
||||
- `logs` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `device logs` with the alias.
|
||||
@ -1613,6 +1651,43 @@ comma-separated list (no blank spaces) of device UUIDs to be moved
|
||||
|
||||
fleet name or slug (preferred)
|
||||
|
||||
## device note
|
||||
|
||||
### Aliases
|
||||
|
||||
- `notes` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `device note` with the alias.
|
||||
|
||||
### Description
|
||||
|
||||
Set or update a device note. If the note argument is not provided,
|
||||
it will be read from stdin.
|
||||
|
||||
To view device notes, use the `balena device <uuid>` command.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena device note "My useful note" --device 7cf02a6
|
||||
$ cat note.txt | balena device note --device 7cf02a6
|
||||
|
||||
### Arguments
|
||||
|
||||
#### NOTE
|
||||
|
||||
note content
|
||||
|
||||
### Options
|
||||
|
||||
#### -d, --device DEVICE
|
||||
|
||||
device UUID
|
||||
|
||||
#### --dev DEV
|
||||
|
||||
|
||||
|
||||
## device os-update
|
||||
|
||||
### Description
|
||||
@ -1674,8 +1749,6 @@ the uuid of the device to pin to a release
|
||||
|
||||
the commit of the release for the device to get pinned to
|
||||
|
||||
### Options
|
||||
|
||||
## device public-url
|
||||
|
||||
### Description
|
||||
@ -1732,8 +1805,6 @@ Examples:
|
||||
|
||||
comma-separated list (no blank spaces) of device UUIDs
|
||||
|
||||
### Options
|
||||
|
||||
## device reboot
|
||||
|
||||
### Description
|
||||
@ -1795,7 +1866,7 @@ custom uuid
|
||||
|
||||
#### --deviceType DEVICETYPE
|
||||
|
||||
device type slug (run 'balena devices supported' for possible values)
|
||||
device type slug (run 'balena device-type list' for possible values)
|
||||
|
||||
## device rename
|
||||
|
||||
@ -1820,8 +1891,6 @@ the uuid of the device to rename
|
||||
|
||||
the new name for the device
|
||||
|
||||
### Options
|
||||
|
||||
## device restart
|
||||
|
||||
### Description
|
||||
@ -1907,7 +1976,7 @@ force action if the update lock is set
|
||||
|
||||
### Aliases
|
||||
|
||||
- `ssh`
|
||||
- `ssh` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `device ssh` with the alias.
|
||||
@ -2001,8 +2070,6 @@ comma-separated list (no blank spaces) of device UUIDs
|
||||
|
||||
comma-separated list (no blank spaces) of service names
|
||||
|
||||
### Options
|
||||
|
||||
## device stop-service
|
||||
|
||||
### Description
|
||||
@ -2027,8 +2094,6 @@ comma-separated list (no blank spaces) of device UUIDs
|
||||
|
||||
comma-separated list (no blank spaces) of service names
|
||||
|
||||
### Options
|
||||
|
||||
## device track-fleet
|
||||
|
||||
### Description
|
||||
@ -2045,30 +2110,65 @@ Examples:
|
||||
|
||||
the uuid of the device to make track the fleet's release
|
||||
|
||||
### Options
|
||||
## device tunnel
|
||||
|
||||
## devices supported
|
||||
### Aliases
|
||||
|
||||
- `tunnel` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `device tunnel` with the alias.
|
||||
|
||||
### Description
|
||||
|
||||
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
|
||||
Use this command to open local TCP ports that tunnel to listening sockets in a
|
||||
balenaOS device.
|
||||
|
||||
The --json option is recommended when scripting the output of this command,
|
||||
because the JSON format is less likely to change and it better represents data
|
||||
types like lists and empty strings (for example, the ALIASES column contains a
|
||||
list of zero or more values). The 'jq' utility may be helpful in shell scripts
|
||||
(https://stedolan.github.io/jq/manual/).
|
||||
For example, this command could be used to expose the ssh server of a balenaOS
|
||||
device (port number 22222) on the local machine, or to expose a web server
|
||||
running on the device. The port numbers do not have be the same between the
|
||||
device and the local machine, and multiple ports may be tunneled in a single
|
||||
command line.
|
||||
|
||||
Port mappings are specified in the format: <remotePort>[:[localIP:]localPort]
|
||||
localIP defaults to 'localhost', and localPort defaults to the specified
|
||||
remotePort value.
|
||||
|
||||
Note: the -p (--port) flag must be provided at the end of the command line,
|
||||
as per examples.
|
||||
|
||||
In the case of openBalena, the tunnel command in CLI v12.38.5 or later requires
|
||||
openBalena v3.1.2 or later. Older CLI versions work with older openBalena
|
||||
versions.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena devices supported
|
||||
$ balena devices supported --json
|
||||
# map remote port 22222 to localhost:22222
|
||||
$ balena device tunnel myFleet -p 22222
|
||||
|
||||
# map remote port 22222 to localhost:222
|
||||
$ balena device tunnel 2ead211 -p 22222:222
|
||||
|
||||
# map remote port 22222 to any address on your host machine, port 22222
|
||||
$ balena device tunnel 1546690 -p 22222:0.0.0.0
|
||||
|
||||
# map remote port 22222 to any address on your host machine, port 222
|
||||
$ balena device tunnel myFleet -p 22222:0.0.0.0:222
|
||||
|
||||
# multiple port tunnels can be specified at any one time
|
||||
$ balena device tunnel myFleet -p 8080:3000 -p 8081:9000
|
||||
|
||||
### Arguments
|
||||
|
||||
#### DEVICEORFLEET
|
||||
|
||||
device UUID or fleet name/slug
|
||||
|
||||
### Options
|
||||
|
||||
#### -j, --json
|
||||
#### -p, --port PORT
|
||||
|
||||
produce JSON output instead of tabular output
|
||||
port mapping in the format <remotePort>[:[localIP:]localPort]
|
||||
|
||||
# Environment Variables
|
||||
|
||||
@ -2076,7 +2176,7 @@ produce JSON output instead of tabular output
|
||||
|
||||
### Aliases
|
||||
|
||||
- `envs`
|
||||
- `envs` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `env list` with the alias.
|
||||
@ -2294,7 +2394,7 @@ do not prompt for confirmation before deleting the variable
|
||||
|
||||
### Aliases
|
||||
|
||||
- `env add`
|
||||
- `env add` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `env set` with the alias.
|
||||
@ -2388,7 +2488,7 @@ should be provided. Organization handles can be listed with the
|
||||
`balena organization list` command.
|
||||
|
||||
The fleet's default device type is specified with the `--type` option.
|
||||
The `balena devices supported` command can be used to list the available
|
||||
The `balena device-type list` command can be used to list the available
|
||||
device types.
|
||||
|
||||
Interactive dropdowns will be shown for selection if no device type or
|
||||
@ -2417,7 +2517,7 @@ handle of the organization the fleet should belong to
|
||||
|
||||
#### -t, --type TYPE
|
||||
|
||||
fleet device type (Check available types with `balena devices supported`)
|
||||
fleet device type (Check available types with `balena device-type list`)
|
||||
|
||||
## fleet
|
||||
|
||||
@ -2461,7 +2561,7 @@ produce JSON output instead of tabular output
|
||||
|
||||
### Aliases
|
||||
|
||||
- `fleets`
|
||||
- `fleets` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `fleet list` with the alias.
|
||||
@ -2506,8 +2606,6 @@ the slug of the fleet to pin to a release
|
||||
|
||||
the commit of the release for the fleet to get pinned to
|
||||
|
||||
### Options
|
||||
|
||||
## fleet purge
|
||||
|
||||
### Description
|
||||
@ -2536,8 +2634,6 @@ Examples:
|
||||
|
||||
fleet name or slug (preferred)
|
||||
|
||||
### Options
|
||||
|
||||
## fleet rename
|
||||
|
||||
### Description
|
||||
@ -2573,8 +2669,6 @@ fleet name or slug (preferred)
|
||||
|
||||
the new name for the fleet
|
||||
|
||||
### Options
|
||||
|
||||
## fleet restart
|
||||
|
||||
### Description
|
||||
@ -2602,8 +2696,6 @@ Examples:
|
||||
|
||||
fleet name or slug (preferred)
|
||||
|
||||
### Options
|
||||
|
||||
## fleet rm
|
||||
|
||||
### Description
|
||||
@ -2657,8 +2749,6 @@ Examples:
|
||||
|
||||
the slug of the fleet to make track the latest release
|
||||
|
||||
### Options
|
||||
|
||||
# Local
|
||||
|
||||
## local configure
|
||||
@ -2678,8 +2768,6 @@ Examples:
|
||||
|
||||
path of drive or image to configure
|
||||
|
||||
### Options
|
||||
|
||||
## local flash
|
||||
|
||||
### Description
|
||||
@ -2714,100 +2802,13 @@ Check `balena util available-drives` for available options.
|
||||
|
||||
answer "yes" to all questions (non interactive use)
|
||||
|
||||
# Network
|
||||
|
||||
## tunnel
|
||||
|
||||
### Description
|
||||
|
||||
Use this command to open local TCP ports that tunnel to listening sockets in a
|
||||
balenaOS device.
|
||||
|
||||
For example, this command could be used to expose the ssh server of a balenaOS
|
||||
device (port number 22222) on the local machine, or to expose a web server
|
||||
running on the device. The port numbers do not have be the same between the
|
||||
device and the local machine, and multiple ports may be tunneled in a single
|
||||
command line.
|
||||
|
||||
Port mappings are specified in the format: <remotePort>[:[localIP:]localPort]
|
||||
localIP defaults to 'localhost', and localPort defaults to the specified
|
||||
remotePort value.
|
||||
|
||||
Note: the -p (--port) flag must be provided at the end of the command line,
|
||||
as per examples.
|
||||
|
||||
In the case of openBalena, the tunnel command in CLI v12.38.5 or later requires
|
||||
openBalena v3.1.2 or later. Older CLI versions work with older openBalena
|
||||
versions.
|
||||
|
||||
Examples:
|
||||
|
||||
# map remote port 22222 to localhost:22222
|
||||
$ balena tunnel myFleet -p 22222
|
||||
|
||||
# map remote port 22222 to localhost:222
|
||||
$ balena tunnel 2ead211 -p 22222:222
|
||||
|
||||
# map remote port 22222 to any address on your host machine, port 22222
|
||||
$ balena tunnel 1546690 -p 22222:0.0.0.0
|
||||
|
||||
# map remote port 22222 to any address on your host machine, port 222
|
||||
$ balena tunnel myFleet -p 22222:0.0.0.0:222
|
||||
|
||||
# multiple port tunnels can be specified at any one time
|
||||
$ balena tunnel myFleet -p 8080:3000 -p 8081:9000
|
||||
|
||||
### Arguments
|
||||
|
||||
#### DEVICEORFLEET
|
||||
|
||||
device UUID or fleet name/slug
|
||||
|
||||
### Options
|
||||
|
||||
#### -p, --port PORT
|
||||
|
||||
port mapping in the format <remotePort>[:[localIP:]localPort]
|
||||
|
||||
# Notes
|
||||
|
||||
## notes
|
||||
|
||||
### Description
|
||||
|
||||
Set or update a device note. If the note argument is not provided,
|
||||
it will be read from stdin.
|
||||
|
||||
To view device notes, use the `balena device <uuid>` command.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena note "My useful note" --device 7cf02a6
|
||||
$ cat note.txt | balena note --device 7cf02a6
|
||||
|
||||
### Arguments
|
||||
|
||||
#### NOTE
|
||||
|
||||
note content
|
||||
|
||||
### Options
|
||||
|
||||
#### -d, --device DEVICE
|
||||
|
||||
device UUID
|
||||
|
||||
#### --dev DEV
|
||||
|
||||
|
||||
|
||||
# Organizations
|
||||
|
||||
## organization list
|
||||
|
||||
### Aliases
|
||||
|
||||
- `orgs`
|
||||
- `orgs` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `organization list` with the alias.
|
||||
@ -2820,8 +2821,6 @@ Examples:
|
||||
|
||||
$ balena organization list
|
||||
|
||||
### Options
|
||||
|
||||
# OS
|
||||
|
||||
## os build-config
|
||||
@ -2988,7 +2987,7 @@ expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)
|
||||
### Description
|
||||
|
||||
Download an unconfigured OS image for the specified device type.
|
||||
Check available device types with 'balena devices supported'.
|
||||
Check available device types with 'balena device-type list'.
|
||||
|
||||
Note: Currently this command only works with balenaCloud, not openBalena.
|
||||
If using openBalena, please download the OS from: https://www.balena.io/os/
|
||||
@ -3067,7 +3066,7 @@ path to OS image
|
||||
|
||||
#### -t, --type TYPE
|
||||
|
||||
device type (Check available types with `balena devices supported`)
|
||||
device type (Check available types with `balena device-type list`)
|
||||
|
||||
#### -d, --drive DRIVE
|
||||
|
||||
@ -3084,7 +3083,7 @@ answer "yes" to all questions (non interactive use)
|
||||
### Description
|
||||
|
||||
Show the available balenaOS versions for the given device type.
|
||||
Check available types with `balena devices supported`.
|
||||
Check available types with `balena device-type list`.
|
||||
|
||||
balenaOS ESR versions can be listed with the '--esr' option. See also:
|
||||
https://www.balena.io/docs/reference/OS/extended-support-release/
|
||||
@ -3192,8 +3191,6 @@ Examples:
|
||||
|
||||
the device IP or hostname
|
||||
|
||||
### Options
|
||||
|
||||
# Preload
|
||||
|
||||
## preload
|
||||
@ -3252,9 +3249,9 @@ fleet name or slug (preferred)
|
||||
|
||||
The commit hash of the release to preload. Use "current" to specify the current
|
||||
release (ignored if no appId is given). The current release is usually also the
|
||||
latest, but can be pinned to a specific release. See:
|
||||
https://www.balena.io/docs/learn/deploy/release-strategy/release-policy/
|
||||
https://www.balena.io/docs/learn/more/masterclasses/fleet-management/#63-pin-using-the-api
|
||||
latest, but can be pinned to a specific release. See:
|
||||
https://www.balena.io/docs/learn/deploy/release-strategy/release-policy/
|
||||
https://www.balena.io/docs/learn/more/masterclasses/fleet-management/#63-pin-using-the-api
|
||||
https://github.com/balena-io-examples/staged-releases
|
||||
|
||||
#### -s, --splash-image SPLASH-IMAGE
|
||||
@ -3561,8 +3558,6 @@ Examples:
|
||||
|
||||
the commit or ID of the release to finalize
|
||||
|
||||
### Options
|
||||
|
||||
## release
|
||||
|
||||
### Description
|
||||
@ -3616,13 +3611,11 @@ Examples:
|
||||
|
||||
the commit or ID of the release to invalidate
|
||||
|
||||
### Options
|
||||
|
||||
## release list
|
||||
|
||||
### Aliases
|
||||
|
||||
- `releases`
|
||||
- `releases` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `release list` with the alias.
|
||||
@ -3683,8 +3676,6 @@ Examples:
|
||||
|
||||
the commit or ID of the release to validate
|
||||
|
||||
### Options
|
||||
|
||||
# Settings
|
||||
|
||||
## settings
|
||||
@ -3697,15 +3688,13 @@ Examples:
|
||||
|
||||
$ balena settings
|
||||
|
||||
### Options
|
||||
|
||||
# SSH Keys
|
||||
|
||||
## ssh-key add
|
||||
|
||||
### Aliases
|
||||
|
||||
- `key add`
|
||||
- `key add` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `ssh-key add` with the alias.
|
||||
@ -3747,13 +3736,11 @@ the SSH key name
|
||||
|
||||
the path to the public key file
|
||||
|
||||
### Options
|
||||
|
||||
## ssh-key
|
||||
|
||||
### Aliases
|
||||
|
||||
- `key`
|
||||
- `key` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `ssh-key` with the alias.
|
||||
@ -3772,14 +3759,12 @@ Examples:
|
||||
|
||||
balenaCloud ID for the SSH key
|
||||
|
||||
### Options
|
||||
|
||||
## ssh-key list
|
||||
|
||||
### Aliases
|
||||
|
||||
- `keys`
|
||||
- `key list`
|
||||
- `keys` *(deprecated)*
|
||||
- `key list` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `ssh-key list` with the alias.
|
||||
@ -3792,13 +3777,11 @@ Examples:
|
||||
|
||||
$ balena ssh-key list
|
||||
|
||||
### Options
|
||||
|
||||
## ssh-key rm
|
||||
|
||||
### Aliases
|
||||
|
||||
- `key rm`
|
||||
- `key rm` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `ssh-key rm` with the alias.
|
||||
@ -3884,7 +3867,7 @@ length of time to enable support for, in (h)ours or (d)ays, e.g. 12h, 2d
|
||||
|
||||
### Aliases
|
||||
|
||||
- `tags`
|
||||
- `tags` *(deprecated)*
|
||||
|
||||
|
||||
To use one of the aliases, replace `tag list` with the alias.
|
||||
@ -4033,8 +4016,6 @@ release id
|
||||
List available drives which are usable for writing an OS image to.
|
||||
Does not list system drives.
|
||||
|
||||
### Options
|
||||
|
||||
# Version
|
||||
|
||||
## version
|
||||
|
32
eslint.config.js
Normal file
32
eslint.config.js
Normal file
@ -0,0 +1,32 @@
|
||||
const { FlatCompat } = require('@eslint/eslintrc');
|
||||
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
});
|
||||
module.exports = [
|
||||
...require('@balena/lint/config/eslint.config'),
|
||||
...compat.config({
|
||||
parserOptions: {
|
||||
project: 'tsconfig.dev.json',
|
||||
},
|
||||
ignorePatterns: ['**/generate-completion.js', '**/bin/**/*'],
|
||||
rules: {
|
||||
ignoreDefinitionFiles: 0,
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-shadow': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
|
||||
|
||||
'no-restricted-imports': ['error', {
|
||||
paths: ['resin-cli-visuals', 'chalk', 'common-tags', 'resin-cli-form'],
|
||||
}],
|
||||
|
||||
'@typescript-eslint/no-unused-vars': ['error', {
|
||||
argsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
}],
|
||||
},
|
||||
}),
|
||||
];
|
6114
npm-shrinkwrap.json
generated
6114
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
31
package.json
31
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "balena-cli",
|
||||
"version": "19.13.1",
|
||||
"version": "21.1.6",
|
||||
"description": "The official balena Command Line Interface",
|
||||
"main": "./build/app.js",
|
||||
"homepage": "https://github.com/balena-io/balena-cli",
|
||||
@ -58,6 +58,7 @@
|
||||
"build:completion": "node completion/generate-completion.js",
|
||||
"build:standalone": "ts-node --transpile-only automation/run.ts build:standalone",
|
||||
"build:installer": "ts-node --transpile-only automation/run.ts build:installer",
|
||||
"deduplicate-dependencies": "npm dd && git add npm-shrinkwrap.json && git commit --message \"Deduplicate dependencies\"",
|
||||
"package": "npm run build:fast && npm run build:standalone && npm run build:installer",
|
||||
"pretest": "npm run build",
|
||||
"test": "npm run test:shrinkwrap && npm run test:core",
|
||||
@ -111,7 +112,7 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@balena/lint": "^8.0.0",
|
||||
"@balena/lint": "^9.1.3",
|
||||
"@electron/notarize": "^2.0.0",
|
||||
"@types/archiver": "^6.0.2",
|
||||
"@types/bluebird": "^3.5.36",
|
||||
@ -180,27 +181,27 @@
|
||||
"mock-fs": "^5.2.0",
|
||||
"mock-require": "^3.0.3",
|
||||
"nock": "^13.2.1",
|
||||
"oclif": "^4.14.0",
|
||||
"oclif": "^4.17.0",
|
||||
"rewire": "^7.0.0",
|
||||
"simple-git": "^3.14.1",
|
||||
"sinon": "^19.0.0",
|
||||
"string-to-stream": "^3.0.1",
|
||||
"ts-node": "^10.4.0",
|
||||
"typescript": "^5.6.2"
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@balena/compose": "^4.0.1",
|
||||
"@balena/compose": "^7.0.1",
|
||||
"@balena/dockerignore": "^1.0.2",
|
||||
"@balena/env-parsing": "^1.1.8",
|
||||
"@balena/es-version": "^1.0.1",
|
||||
"@oclif/core": "^4.0.25",
|
||||
"@oclif/core": "^4.1.0",
|
||||
"@sentry/node": "^6.16.1",
|
||||
"balena-config-json": "^4.2.0",
|
||||
"balena-device-init": "^7.0.1",
|
||||
"balena-config-json": "^4.2.2",
|
||||
"balena-device-init": "^8.1.3",
|
||||
"balena-errors": "^4.7.3",
|
||||
"balena-image-fs": "^7.0.6",
|
||||
"balena-preload": "^15.0.6",
|
||||
"balena-sdk": "^19.7.3",
|
||||
"balena-image-fs": "^7.5.0",
|
||||
"balena-preload": "^18.0.1",
|
||||
"balena-sdk": "^21.3.0",
|
||||
"balena-semver": "^2.3.0",
|
||||
"balena-settings-client": "^5.0.2",
|
||||
"balena-settings-storage": "^8.1.0",
|
||||
@ -211,10 +212,11 @@
|
||||
"cli-truncate": "^2.1.0",
|
||||
"color-hash": "^1.1.1",
|
||||
"common-tags": "^1.7.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"denymount": "^2.3.0",
|
||||
"docker-modem": "^5.0.3",
|
||||
"docker-modem": "^5.0.6",
|
||||
"docker-progress": "^5.1.3",
|
||||
"dockerode": "^4.0.2",
|
||||
"dockerode": "^4.0.5",
|
||||
"ejs": "^3.1.6",
|
||||
"etcher-sdk": "9.1.0",
|
||||
"express": "^4.17.2",
|
||||
@ -231,6 +233,7 @@
|
||||
"is-root": "^2.1.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"JSONStream": "^1.0.3",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"livepush": "^3.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mime": "^2.4.6",
|
||||
@ -273,6 +276,6 @@
|
||||
}
|
||||
},
|
||||
"versionist": {
|
||||
"publishedAt": "2024-10-21T19:13:32.213Z"
|
||||
"publishedAt": "2025-04-03T14:12:06.976Z"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
diff --git a/node_modules/@oclif/core/lib/help/command.js b/node_modules/@oclif/core/lib/help/command.js
|
||||
index 90922c8..6b7f417 100644
|
||||
index 33105a0..0436982 100644
|
||||
--- a/node_modules/@oclif/core/lib/help/command.js
|
||||
+++ b/node_modules/@oclif/core/lib/help/command.js
|
||||
@@ -58,7 +58,8 @@ class CommandHelp extends formatter_1.HelpFormatter {
|
||||
@ -13,10 +13,10 @@ index 90922c8..6b7f417 100644
|
||||
if (a.default)
|
||||
description = `${(0, theme_1.colorize)(this.config?.theme?.flagDefaultValue, `[default: ${a.default}]`)} ${description}`;
|
||||
diff --git a/node_modules/@oclif/core/lib/help/index.js b/node_modules/@oclif/core/lib/help/index.js
|
||||
index 4a34b89..d7eb6ac 100644
|
||||
index 0b48c0e..ff4fed4 100644
|
||||
--- a/node_modules/@oclif/core/lib/help/index.js
|
||||
+++ b/node_modules/@oclif/core/lib/help/index.js
|
||||
@@ -172,11 +172,12 @@ class Help extends HelpBase {
|
||||
@@ -173,11 +173,12 @@ class Help extends HelpBase {
|
||||
}
|
||||
this.log(this.formatCommand(command));
|
||||
this.log('');
|
@ -1,8 +1,8 @@
|
||||
diff --git a/node_modules/oclif/lib/commands/pack/win.js b/node_modules/oclif/lib/commands/pack/win.js
|
||||
index ef7f90e..8264b7c 100644
|
||||
index bfe9205..482519e 100644
|
||||
--- a/node_modules/oclif/lib/commands/pack/win.js
|
||||
+++ b/node_modules/oclif/lib/commands/pack/win.js
|
||||
@@ -76,6 +76,12 @@ InstallDir "\$PROGRAMFILES${arch === 'x64' ? '64' : ''}\\${config.dirname}"
|
||||
@@ -86,6 +86,12 @@ InstallDir "\$PROGRAMFILES${arch === 'x64' ? '64' : ''}\\${config.dirname}"
|
||||
${customization}
|
||||
|
||||
Section "${config.name} CLI \${VERSION}"
|
||||
@ -16,20 +16,18 @@ index ef7f90e..8264b7c 100644
|
||||
File /r bin
|
||||
File /r client
|
||||
diff --git a/node_modules/oclif/lib/tarballs/build.js b/node_modules/oclif/lib/tarballs/build.js
|
||||
index 14d5a6e..7b42a6f 100644
|
||||
index f0c8d95..a72400e 100644
|
||||
--- a/node_modules/oclif/lib/tarballs/build.js
|
||||
+++ b/node_modules/oclif/lib/tarballs/build.js
|
||||
@@ -200,6 +200,13 @@ const extractCLI = async (tarball, c) => {
|
||||
@@ -218,6 +218,11 @@ const extractCLI = async (tarball, c) => {
|
||||
(0, promises_1.rm)(path.join(workspace, path.basename(tarball)), { recursive: true }),
|
||||
(0, fs_extra_1.remove)(path.join(workspace, 'bin', 'run.cmd')),
|
||||
]);
|
||||
+
|
||||
+ // The oclif installers are a production installation, while the source
|
||||
+ // `bin` folder may contain a `.fast-boot.json` file of a dev installation.
|
||||
+ // This has previously led to issues preventing the CLI from starting, so
|
||||
+ // delete `.fast-boot.json` (if any) from the destination folder.
|
||||
+ await (0, fs_extra_1.remove)(path.join(workspace, 'bin', '.fast-boot.json'));
|
||||
+
|
||||
};
|
||||
const buildTarget = async (target, c, options) => {
|
||||
const workspace = c.workspace(target);
|
||||
if (target.platform === 'win32' && target.arch === 'arm64' && (0, semver_1.lt)(c.nodeVersion, '20.0.0')) {
|
4
repo.yml
4
repo.yml
@ -6,6 +6,10 @@ upstream:
|
||||
url: 'https://github.com/balena-io/balena-sdk'
|
||||
- repo: 'balena-config-json'
|
||||
url: 'https://github.com/balena-io-modules/balena-config-json'
|
||||
- repo: 'balena-image-fs'
|
||||
url: 'https://github.com/balena-io-modules/balena-image-fs'
|
||||
- repo: 'balena-device-init'
|
||||
url: 'https://github.com/balena-io-modules/balena-device-init'
|
||||
- repo: 'balena-image-manager'
|
||||
url: 'https://github.com/balena-io-modules/balena-image-manager'
|
||||
- repo: 'balena-preload'
|
||||
|
@ -101,11 +101,9 @@ async function init() {
|
||||
|
||||
/** Execute the oclif parser and the CLI command. */
|
||||
async function oclifRun(command: string[], options: AppOptions) {
|
||||
let deprecationPromise: Promise<void>;
|
||||
let deprecationPromise: Promise<void> | undefined;
|
||||
// check and enforce the CLI's deprecation policy
|
||||
if (unsupportedFlag || process.env.BALENARC_UNSUPPORTED) {
|
||||
deprecationPromise = Promise.resolve();
|
||||
} else {
|
||||
if (!(unsupportedFlag || process.env.BALENARC_UNSUPPORTED)) {
|
||||
const { DeprecationChecker } = await import('./deprecation');
|
||||
const deprecationChecker = new DeprecationChecker(packageJSON.version);
|
||||
// warnAndAbortIfDeprecated uses previously cached data only
|
||||
|
@ -17,8 +17,28 @@
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { getBalenaSdk, getCliForm, stripIndent } from '../../utils/lazy';
|
||||
import {
|
||||
formatDuration,
|
||||
intervalToDuration,
|
||||
isValid,
|
||||
parseISO,
|
||||
} from 'date-fns';
|
||||
|
||||
// In days
|
||||
const durations = [1, 7, 30, 90];
|
||||
|
||||
async function isLoggedInWithJwt() {
|
||||
const balena = getBalenaSdk();
|
||||
try {
|
||||
const token = await balena.auth.getToken();
|
||||
const { default: jwtDecode } = await import('jwt-decode');
|
||||
jwtDecode(token);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default class GenerateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -30,17 +50,21 @@ export default class GenerateCmd extends Command {
|
||||
This key can be used to log into the CLI using 'balena login --token <key>',
|
||||
or to authenticate requests to the API with an 'Authorization: Bearer <key>' header.
|
||||
`;
|
||||
public static examples = ['$ balena api-key generate "Jenkins Key"'];
|
||||
public static examples = [
|
||||
'$ balena api-key generate "Jenkins Key"',
|
||||
'$ balena api-key generate "Jenkins Key" 2025-10-30',
|
||||
'$ balena api-key generate "Jenkins Key" never',
|
||||
];
|
||||
|
||||
public static args = {
|
||||
name: Args.string({
|
||||
description: 'the API key name',
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
expiryDate: Args.string({
|
||||
description:
|
||||
'the expiry date of the API key as an ISO date string, or "never" for no expiry',
|
||||
}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -48,11 +72,70 @@ export default class GenerateCmd extends Command {
|
||||
public async run() {
|
||||
const { args: params } = await this.parse(GenerateCmd);
|
||||
|
||||
let expiryDateResponse: string | number | undefined = params.expiryDate;
|
||||
let key;
|
||||
try {
|
||||
key = await getBalenaSdk().models.apiKey.create(params.name);
|
||||
if (!expiryDateResponse) {
|
||||
expiryDateResponse = await getCliForm().ask({
|
||||
message: 'Please pick an expiry date for the API key',
|
||||
type: 'list',
|
||||
choices: [...durations, 'custom', 'never'].map((duration) => ({
|
||||
name:
|
||||
duration === 'never'
|
||||
? 'No expiration'
|
||||
: typeof duration === 'number'
|
||||
? formatDuration(
|
||||
intervalToDuration({
|
||||
start: 0,
|
||||
end: duration * 24 * 60 * 60 * 1000,
|
||||
}),
|
||||
)
|
||||
: 'Custom expiration',
|
||||
value: duration,
|
||||
})),
|
||||
});
|
||||
}
|
||||
let expiryDate: Date | null;
|
||||
if (expiryDateResponse === 'never') {
|
||||
expiryDate = null;
|
||||
} else if (expiryDateResponse === 'custom') {
|
||||
do {
|
||||
expiryDate = parseISO(
|
||||
await getCliForm().ask({
|
||||
message:
|
||||
'Please enter an expiry date for the API key as an ISO date string',
|
||||
type: 'input',
|
||||
}),
|
||||
);
|
||||
if (!isValid(expiryDate)) {
|
||||
console.error('Invalid date format');
|
||||
}
|
||||
} while (!isValid(expiryDate));
|
||||
} else if (typeof expiryDateResponse === 'string') {
|
||||
expiryDate = parseISO(expiryDateResponse);
|
||||
if (!isValid(expiryDate)) {
|
||||
throw new Error(
|
||||
'Invalid date format, please use a valid ISO date string',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
expiryDate = new Date(
|
||||
Date.now() + expiryDateResponse * 24 * 60 * 60 * 1000,
|
||||
);
|
||||
}
|
||||
key = await getBalenaSdk().models.apiKey.create({
|
||||
name: params.name,
|
||||
expiryDate: expiryDate === null ? null : expiryDate.toISOString(),
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.name === 'BalenaNotLoggedIn') {
|
||||
if (await isLoggedInWithJwt()) {
|
||||
throw new ExpectedError(stripIndent`
|
||||
This command requires you to have been recently authenticated.
|
||||
Please login again with 'balena login'.
|
||||
In case you are using the Web authorization method, you need to logout and re-login to the dashboard first.
|
||||
`);
|
||||
}
|
||||
throw new ExpectedError(stripIndent`
|
||||
This command cannot be run when logged in with an API key.
|
||||
Please login again with 'balena login' and select an alternative method.
|
||||
|
@ -21,6 +21,7 @@ import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class APIKeyListCmd extends Command {
|
||||
public static aliases = ['api-keys'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Print a list of balenaCloud API keys.
|
||||
@ -32,7 +33,6 @@ export default class APIKeyListCmd extends Command {
|
||||
public static examples = ['$ balena api-key list'];
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
user: Flags.boolean({
|
||||
char: 'u',
|
||||
description: 'show API keys for your user',
|
||||
@ -51,7 +51,7 @@ export default class APIKeyListCmd extends Command {
|
||||
await getApplication(getBalenaSdk(), options.fleet, {
|
||||
$select: 'actor',
|
||||
})
|
||||
).actor
|
||||
).actor.__id
|
||||
: await getBalenaSdk().auth.getActorId();
|
||||
const keys = await getBalenaSdk().pine.get({
|
||||
resource: 'api_key',
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class RevokeCmd extends Command {
|
||||
@ -40,10 +39,6 @@ export default class RevokeCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
@ -55,9 +50,9 @@ export default class RevokeCmd extends Command {
|
||||
return;
|
||||
}
|
||||
await Promise.all(
|
||||
apiKeyIds.map(
|
||||
async (id) => await getBalenaSdk().models.apiKey.revoke(Number(id)),
|
||||
),
|
||||
apiKeyIds.map(async (id) => {
|
||||
await getBalenaSdk().models.apiKey.revoke(Number(id));
|
||||
}),
|
||||
);
|
||||
console.log('Successfully revoked the given API keys');
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class AppCreateCmd extends Command {
|
||||
@ -31,7 +30,7 @@ export default class AppCreateCmd extends Command {
|
||||
\`balena organization list\` command.
|
||||
|
||||
The app's default device type is specified with the \`--type\` option.
|
||||
The \`balena devices supported\` command can be used to list the available
|
||||
The \`balena device-type list\` command can be used to list the available
|
||||
device types.
|
||||
|
||||
Interactive dropdowns will be shown for selection if no device type or
|
||||
@ -62,9 +61,8 @@ export default class AppCreateCmd extends Command {
|
||||
type: Flags.string({
|
||||
char: 't',
|
||||
description:
|
||||
'app device type (Check available types with `balena devices supported`)',
|
||||
'app device type (Check available types with `balena device-type list`)',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class BlockCreateCmd extends Command {
|
||||
@ -31,7 +30,7 @@ export default class BlockCreateCmd extends Command {
|
||||
\`balena organization list\` command.
|
||||
|
||||
The block's default device type is specified with the \`--type\` option.
|
||||
The \`balena devices supported\` command can be used to list the available
|
||||
The \`balena device-type list\` command can be used to list the available
|
||||
device types.
|
||||
|
||||
Interactive dropdowns will be shown for selection if no device type or
|
||||
@ -62,9 +61,8 @@ export default class BlockCreateCmd extends Command {
|
||||
type: Flags.string({
|
||||
char: 't',
|
||||
description:
|
||||
'block device type (Check available types with `balena devices supported`)',
|
||||
'block device type (Check available types with `balena device-type list`)',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -36,15 +36,16 @@ import { buildProject, composeCliFlags } from '../../utils/compose_ts';
|
||||
import type { BuildOpts, DockerCliFlags } from '../../utils/docker';
|
||||
import { dockerCliFlags } from '../../utils/docker';
|
||||
|
||||
// TODO: For this special one we can't use Interfaces.InferredFlags/InferredArgs
|
||||
// because of the 'registry-secrets' type which is defined in the actual code
|
||||
// as a path (string | undefined) but then the cli turns it into an object
|
||||
interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
|
||||
type ComposeGenerateOptsParam = Parameters<typeof compose.generateOpts>[0];
|
||||
|
||||
interface PrepareBuildOpts
|
||||
extends ComposeCliFlags,
|
||||
DockerCliFlags,
|
||||
ComposeGenerateOptsParam {
|
||||
arch?: string;
|
||||
deviceType?: string;
|
||||
fleet?: string;
|
||||
source?: string; // Not part of command profile - source param copied here.
|
||||
help: void;
|
||||
source?: string;
|
||||
}
|
||||
|
||||
export default class BuildCmd extends Command {
|
||||
@ -95,9 +96,6 @@ ${dockerignoreHelp}
|
||||
fleet: cf.fleet,
|
||||
...composeCliFlags,
|
||||
...dockerCliFlags,
|
||||
// NOTE: Not supporting -h for help, because of clash with -h in DockerCliFlags
|
||||
// Revisit this in future release.
|
||||
help: Flags.help({}),
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
@ -117,29 +115,31 @@ ${dockerignoreHelp}
|
||||
const logger = Logger.getLogger();
|
||||
logger.logDebug('Parsing input...');
|
||||
|
||||
// `build` accepts `source` as a parameter, but compose expects it as an option
|
||||
options.source = params.source;
|
||||
delete params.source;
|
||||
const prepareBuildOpts = {
|
||||
...options,
|
||||
source: params.source,
|
||||
};
|
||||
|
||||
await this.resolveArchFromDeviceType(sdk, options);
|
||||
await this.resolveArchFromDeviceType(sdk, prepareBuildOpts);
|
||||
|
||||
await this.validateOptions(options, sdk);
|
||||
await this.validateOptions(prepareBuildOpts, sdk);
|
||||
|
||||
// Build args are under consideration for removal - warn user
|
||||
if (options.buildArg) {
|
||||
if (prepareBuildOpts.buildArg) {
|
||||
console.log(buildArgDeprecation);
|
||||
}
|
||||
|
||||
const app = await this.getAppAndResolveArch(options);
|
||||
const app = await this.getAppAndResolveArch(prepareBuildOpts);
|
||||
|
||||
const { docker, buildOpts, composeOpts } = await this.prepareBuild(options);
|
||||
const { docker, buildOpts, composeOpts } =
|
||||
await this.prepareBuild(prepareBuildOpts);
|
||||
|
||||
try {
|
||||
await this.buildProject(docker, logger, composeOpts, {
|
||||
appType: app?.application_type?.[0],
|
||||
arch: options.arch!,
|
||||
deviceType: options.deviceType!,
|
||||
buildEmulated: options.emulated,
|
||||
arch: prepareBuildOpts.arch!,
|
||||
deviceType: prepareBuildOpts.deviceType!,
|
||||
buildEmulated: prepareBuildOpts.emulated,
|
||||
buildOpts,
|
||||
});
|
||||
} catch (err) {
|
||||
@ -151,7 +151,7 @@ ${dockerignoreHelp}
|
||||
logger.logSuccess('Build succeeded!');
|
||||
}
|
||||
|
||||
protected async validateOptions(opts: FlagsDef, sdk: BalenaSDK) {
|
||||
protected async validateOptions(opts: PrepareBuildOpts, sdk: BalenaSDK) {
|
||||
// Validate option combinations
|
||||
if (
|
||||
(opts.fleet == null && (opts.arch == null || opts.deviceType == null)) ||
|
||||
@ -179,7 +179,10 @@ ${dockerignoreHelp}
|
||||
opts['registry-secrets'] = registrySecrets;
|
||||
}
|
||||
|
||||
protected async resolveArchFromDeviceType(sdk: BalenaSDK, opts: FlagsDef) {
|
||||
protected async resolveArchFromDeviceType(
|
||||
sdk: BalenaSDK,
|
||||
opts: PrepareBuildOpts,
|
||||
) {
|
||||
if (opts.deviceType != null && opts.arch == null) {
|
||||
try {
|
||||
const deviceTypeOpts = {
|
||||
@ -212,7 +215,7 @@ ${dockerignoreHelp}
|
||||
}
|
||||
}
|
||||
|
||||
protected async getAppAndResolveArch(opts: FlagsDef) {
|
||||
protected async getAppAndResolveArch(opts: PrepareBuildOpts) {
|
||||
if (opts.fleet) {
|
||||
const { getAppWithArch } = await import('../../utils/helpers');
|
||||
const app = await getAppWithArch(opts.fleet);
|
||||
@ -222,7 +225,7 @@ ${dockerignoreHelp}
|
||||
}
|
||||
}
|
||||
|
||||
protected async prepareBuild(options: FlagsDef) {
|
||||
protected async prepareBuild(options: PrepareBuildOpts) {
|
||||
const { getDocker, generateBuildOpts } = await import('../../utils/docker');
|
||||
const [docker, buildOpts, composeOpts] = await Promise.all([
|
||||
getDocker(options),
|
||||
|
@ -82,7 +82,7 @@ export default class ConfigGenerateCmd extends Command {
|
||||
}),
|
||||
deviceType: Flags.string({
|
||||
description:
|
||||
"device type slug (run 'balena devices supported' for possible values)",
|
||||
"device type slug (run 'balena device-type list' for possible values)",
|
||||
}),
|
||||
'generate-device-api-key': Flags.boolean({
|
||||
description: 'generate a fresh device key for the device',
|
||||
@ -117,7 +117,6 @@ export default class ConfigGenerateCmd extends Command {
|
||||
'expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)',
|
||||
exclusive: ['device'],
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -44,7 +44,6 @@ export default class ConfigInjectCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
drive: cf.driveOrImg,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static root = true;
|
||||
|
@ -38,7 +38,6 @@ export default class ConfigReadCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
drive: cf.driveOrImg,
|
||||
help: cf.help,
|
||||
json: cf.json,
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,6 @@ export default class ConfigReconfigureCmd extends Command {
|
||||
description: 'show advanced commands',
|
||||
char: 'v',
|
||||
}),
|
||||
help: cf.help,
|
||||
version: Flags.string({
|
||||
description: 'balenaOS version, for example "2.32.0" or "2.44.0+rev1"',
|
||||
}),
|
||||
|
@ -49,7 +49,6 @@ export default class ConfigWriteCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
drive: cf.driveOrImg,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static root = true;
|
||||
|
@ -60,7 +60,6 @@ interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
|
||||
'release-tag'?: string[];
|
||||
draft: boolean;
|
||||
note?: string;
|
||||
help: void;
|
||||
}
|
||||
|
||||
export default class DeployCmd extends Command {
|
||||
@ -139,9 +138,6 @@ ${dockerignoreHelp}
|
||||
note: Flags.string({ description: 'The notes for this release' }),
|
||||
...composeCliFlags,
|
||||
...dockerCliFlags,
|
||||
// NOTE: Not supporting -h for help, because of clash with -h in DockerCliFlags
|
||||
// Revisit this in future release.
|
||||
help: Flags.help({}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -372,6 +368,7 @@ ${dockerignoreHelp}
|
||||
!opts.shouldUploadLogs,
|
||||
composeOpts.projectPath,
|
||||
opts.createAsDraft,
|
||||
project.descriptors,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -17,14 +17,20 @@
|
||||
import { Flags, Command } from '@oclif/core';
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
import * as _ from 'lodash';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class DevicesSupportedCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
|
||||
export default class DeviceTypeListCmd extends Command {
|
||||
public static aliases = ['devices supported'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
|
||||
public static description = stripIndent`
|
||||
List the device types supported by balena (like 'raspberrypi3' or 'intel-nuc').
|
||||
|
||||
List the device types supported by balena (like 'raspberrypi3' or 'intel-nuc').
|
||||
|
||||
By default, only actively supported device types are listed.
|
||||
The --all option can be used to list all device types, including those that are
|
||||
no longer supported by balena.
|
||||
|
||||
The --json option is recommended when scripting the output of this command,
|
||||
because the JSON format is less likely to change and it better represents data
|
||||
@ -33,20 +39,24 @@ export default class DevicesSupportedCmd extends Command {
|
||||
(https://stedolan.github.io/jq/manual/).
|
||||
`;
|
||||
public static examples = [
|
||||
'$ balena devices supported',
|
||||
'$ balena devices supported --json',
|
||||
'$ balena device-type list',
|
||||
'$ balena device-type list --all',
|
||||
'$ balena device-type list --json',
|
||||
];
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
json: Flags.boolean({
|
||||
char: 'j',
|
||||
description: 'produce JSON output instead of tabular output',
|
||||
}),
|
||||
all: Flags.boolean({
|
||||
description: 'include device types no longer supported by balena',
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run() {
|
||||
const { flags: options } = await this.parse(DevicesSupportedCmd);
|
||||
const { flags: options } = await this.parse(DeviceTypeListCmd);
|
||||
const pineOptions = {
|
||||
$select: ['slug', 'name'],
|
||||
$expand: {
|
||||
@ -57,9 +67,11 @@ export default class DevicesSupportedCmd extends Command {
|
||||
},
|
||||
},
|
||||
} satisfies BalenaSdk.PineOptions<BalenaSdk.DeviceType>;
|
||||
const dts = (await getBalenaSdk().models.deviceType.getAllSupported(
|
||||
pineOptions,
|
||||
)) as Array<
|
||||
const dts = (
|
||||
options.all
|
||||
? await getBalenaSdk().models.deviceType.getAll(pineOptions)
|
||||
: await getBalenaSdk().models.deviceType.getAllSupported(pineOptions)
|
||||
) as Array<
|
||||
BalenaSdk.PineTypedResult<BalenaSdk.DeviceType, typeof pineOptions>
|
||||
>;
|
||||
interface DT {
|
@ -42,7 +42,6 @@ export default class DeviceDeactivateCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -16,11 +16,11 @@
|
||||
*/
|
||||
|
||||
import { Flags, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getCliUx, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class DeviceDetectCmd extends Command {
|
||||
public static aliases = ['scan'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Scan for balenaOS devices on your local network.
|
||||
@ -49,7 +49,6 @@ export default class DeviceDetectCmd extends Command {
|
||||
char: 't',
|
||||
description: 'scan timeout in seconds',
|
||||
}),
|
||||
help: cf.help,
|
||||
json: Flags.boolean({
|
||||
default: false,
|
||||
char: 'j',
|
||||
@ -92,7 +91,7 @@ export default class DeviceDetectCmd extends Command {
|
||||
try {
|
||||
await docker.ping();
|
||||
return true;
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { ExpectedError } from '../../errors';
|
||||
|
||||
@ -35,10 +34,6 @@ export default class DeviceIdentifyCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -63,7 +63,6 @@ export default class DeviceCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
json: cf.json,
|
||||
help: cf.help,
|
||||
view: Flags.boolean({
|
||||
default: false,
|
||||
description: 'open device dashboard page',
|
||||
@ -78,45 +77,59 @@ export default class DeviceCmd extends Command {
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const device = (await balena.models.device.get(
|
||||
params.uuid,
|
||||
options.json
|
||||
? {
|
||||
$expand: {
|
||||
device_tag: {
|
||||
$select: ['tag_key', 'value'],
|
||||
},
|
||||
...expandForAppName.$expand,
|
||||
let device: ExtendedDevice;
|
||||
if (options.json) {
|
||||
const [deviceBase, deviceComputed] = await Promise.all([
|
||||
balena.models.device.get(params.uuid, {
|
||||
$expand: {
|
||||
device_tag: {
|
||||
$select: ['tag_key', 'value'],
|
||||
},
|
||||
}
|
||||
: {
|
||||
$select: [
|
||||
'device_name',
|
||||
'id',
|
||||
'overall_status',
|
||||
'is_online',
|
||||
'ip_address',
|
||||
'mac_address',
|
||||
'last_connectivity_event',
|
||||
'uuid',
|
||||
'supervisor_version',
|
||||
'is_web_accessible',
|
||||
'note',
|
||||
'os_version',
|
||||
'memory_usage',
|
||||
'memory_total',
|
||||
'public_address',
|
||||
'storage_block_device',
|
||||
'storage_usage',
|
||||
'storage_total',
|
||||
'cpu_usage',
|
||||
'cpu_temp',
|
||||
'cpu_id',
|
||||
'is_undervolted',
|
||||
],
|
||||
...expandForAppName,
|
||||
...expandForAppName.$expand,
|
||||
},
|
||||
)) as ExtendedDevice;
|
||||
}),
|
||||
balena.models.device.get(params.uuid, {
|
||||
$select: [
|
||||
'overall_status',
|
||||
'overall_progress',
|
||||
'should_be_running__release',
|
||||
],
|
||||
}),
|
||||
]);
|
||||
|
||||
device = {
|
||||
...deviceBase,
|
||||
...deviceComputed,
|
||||
} as ExtendedDevice;
|
||||
} else {
|
||||
device = (await balena.models.device.get(params.uuid, {
|
||||
$select: [
|
||||
'device_name',
|
||||
'id',
|
||||
'overall_status',
|
||||
'is_online',
|
||||
'ip_address',
|
||||
'mac_address',
|
||||
'last_connectivity_event',
|
||||
'uuid',
|
||||
'supervisor_version',
|
||||
'is_web_accessible',
|
||||
'note',
|
||||
'os_version',
|
||||
'memory_usage',
|
||||
'memory_total',
|
||||
'public_address',
|
||||
'storage_block_device',
|
||||
'storage_usage',
|
||||
'storage_total',
|
||||
'cpu_usage',
|
||||
'cpu_temp',
|
||||
'cpu_id',
|
||||
'is_undervolted',
|
||||
],
|
||||
...expandForAppName,
|
||||
})) as ExtendedDevice;
|
||||
}
|
||||
|
||||
if (options.view) {
|
||||
const open = await import('open');
|
||||
|
@ -28,7 +28,6 @@ interface FlagsDef {
|
||||
'os-version'?: string;
|
||||
drive?: string;
|
||||
config?: string;
|
||||
help: void;
|
||||
'provisioning-key-name'?: string;
|
||||
'provisioning-key-expiry-date'?: string;
|
||||
}
|
||||
@ -100,7 +99,6 @@ export default class DeviceInitCmd extends Command {
|
||||
description:
|
||||
'expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -157,7 +155,7 @@ export default class DeviceInitCmd extends Command {
|
||||
try {
|
||||
logger.logDebug(`Process failed, removing device ${device.uuid}`);
|
||||
await balena.models.device.remove(device.uuid);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// Ignore removal failures, and throw original error
|
||||
}
|
||||
throw e;
|
||||
|
@ -37,6 +37,7 @@ const devicesSelectFields = {
|
||||
|
||||
export default class DeviceListCmd extends Command {
|
||||
public static aliases = ['devices'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
List all devices.
|
||||
@ -58,7 +59,6 @@ export default class DeviceListCmd extends Command {
|
||||
public static flags = {
|
||||
fleet: cf.fleet,
|
||||
json: cf.json,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class DeviceLocalModeCmd extends Command {
|
||||
@ -54,7 +53,6 @@ export default class DeviceLocalModeCmd extends Command {
|
||||
description: 'output boolean indicating local mode status',
|
||||
exclusive: ['enable', 'disable'],
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import type { LogMessage } from 'balena-sdk';
|
||||
|
||||
@ -24,6 +23,7 @@ const MAX_RETRY = 1000;
|
||||
|
||||
export default class DeviceLogsCmd extends Command {
|
||||
public static aliases = ['logs'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Show device logs.
|
||||
@ -86,7 +86,6 @@ export default class DeviceLogsCmd extends Command {
|
||||
'Only show system logs. This can be used in combination with --service.',
|
||||
char: 'S',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
@ -136,7 +135,7 @@ export default class DeviceLogsCmd extends Command {
|
||||
logger.logDebug('Checking we can access device');
|
||||
try {
|
||||
await deviceApi.ping();
|
||||
} catch (e) {
|
||||
} catch {
|
||||
const { ExpectedError } = await import('../../errors');
|
||||
throw new ExpectedError(
|
||||
`Cannot access device at address ${params.device}. Device may not be in local mode.`,
|
||||
|
@ -55,7 +55,6 @@ export default class DeviceMoveCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
fleet: cf.fleet,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -20,7 +20,10 @@ import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class NoteCmd extends Command {
|
||||
export default class DeviceNoteCmd extends Command {
|
||||
public static aliases = ['notes'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Set a device note.
|
||||
|
||||
@ -31,8 +34,8 @@ export default class NoteCmd extends Command {
|
||||
`;
|
||||
|
||||
public static examples = [
|
||||
'$ balena note "My useful note" --device 7cf02a6',
|
||||
'$ cat note.txt | balena note --device 7cf02a6',
|
||||
'$ balena device note "My useful note" --device 7cf02a6',
|
||||
'$ cat note.txt | balena device note --device 7cf02a6',
|
||||
];
|
||||
|
||||
public static args = {
|
||||
@ -47,13 +50,12 @@ export default class NoteCmd extends Command {
|
||||
exclusive: ['device'],
|
||||
hidden: true,
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = await this.parse(NoteCmd);
|
||||
const { args: params, flags: options } = await this.parse(DeviceNoteCmd);
|
||||
|
||||
if (params.note?.length === 0) {
|
||||
throw new ExpectedError('Missing note content');
|
@ -20,6 +20,7 @@ import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
|
||||
import type { Device } from 'balena-sdk';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import { getExpandedProp } from '../../utils/pine';
|
||||
|
||||
export default class DeviceOsUpdateCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -57,7 +58,6 @@ export default class DeviceOsUpdateCmd extends Command {
|
||||
exclusive: ['version'],
|
||||
}),
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -127,27 +127,64 @@ export default class DeviceOsUpdateCmd extends Command {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const choices = await Promise.all(
|
||||
hupVersionInfo.versions.map(async (version) => {
|
||||
const takeoverRequired =
|
||||
(await sdk.models.os.getOsUpdateType(
|
||||
getExpandedProp(is_of__device_type, 'slug')!,
|
||||
currentOsVersion,
|
||||
version,
|
||||
)) === 'takeover';
|
||||
|
||||
return {
|
||||
name: `${version}${hupVersionInfo.recommended === version ? ' (recommended)' : ''}${takeoverRequired ? ' ADVANCED UPDATE: Requires disk re-partitioning with no rollback option' : ''}`,
|
||||
value: version,
|
||||
};
|
||||
}),
|
||||
);
|
||||
targetOsVersion = await getCliForm().ask({
|
||||
message: 'Target OS version',
|
||||
type: 'list',
|
||||
choices: hupVersionInfo.versions.map((version) => ({
|
||||
name:
|
||||
hupVersionInfo.recommended === version
|
||||
? `${version} (recommended)`
|
||||
: version,
|
||||
value: version,
|
||||
})),
|
||||
choices,
|
||||
});
|
||||
}
|
||||
|
||||
const takeoverRequired =
|
||||
(await sdk.models.os.getOsUpdateType(
|
||||
getExpandedProp(is_of__device_type, 'slug')!,
|
||||
currentOsVersion,
|
||||
targetOsVersion,
|
||||
)) === 'takeover';
|
||||
const patterns = await import('../../utils/patterns');
|
||||
// Warn the user if the update requires a takeover
|
||||
if (takeoverRequired) {
|
||||
await patterns.confirm(
|
||||
options.yes || false,
|
||||
stripIndent`Before you proceed, note that this update process is different from a regular HostOS Update:
|
||||
DATA LOSS: This update requires disk re-partitioning, which will erase all data stored on the device.
|
||||
NO ROLLBACK: Unlike our HostOS update mechanism, this process does not allow reverting to a previous version in case of failure.
|
||||
Make sure to back up all important data before continuing. For more details, check our documentation: https://docs.balena.io/reference/OS/updates/update-process/
|
||||
`,
|
||||
);
|
||||
}
|
||||
// Confirm and start update
|
||||
await patterns.confirm(
|
||||
options.yes || false,
|
||||
'Host OS updates require a device restart when they complete. Are you sure you want to proceed?',
|
||||
);
|
||||
|
||||
await sdk.models.device.startOsUpdate(uuid, targetOsVersion);
|
||||
await patterns.awaitDeviceOsUpdate(uuid, targetOsVersion);
|
||||
await sdk.models.device
|
||||
.startOsUpdate(uuid, targetOsVersion, {
|
||||
runDetached: true,
|
||||
})
|
||||
.then(() => {
|
||||
console.log(
|
||||
`The balena OS update has started. You can keep track of the progress via the dashboard.\n` +
|
||||
`To open the dashboard page related to a device via the CLI, you can use \`balena device UUID --view\``,
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(`Failed to start OS update for device ${uuid}:`, error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { getExpandedProp } from '../../utils/pine';
|
||||
|
||||
@ -43,10 +42,6 @@ export default class DevicePinCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
@ -56,7 +51,7 @@ export default class DevicePinCmd extends Command {
|
||||
|
||||
const device = await balena.models.device.get(params.uuid, {
|
||||
$expand: {
|
||||
should_be_running__release: {
|
||||
is_pinned_on__release: {
|
||||
$select: 'commit',
|
||||
},
|
||||
belongs_to__application: {
|
||||
@ -66,7 +61,7 @@ export default class DevicePinCmd extends Command {
|
||||
});
|
||||
|
||||
const pinnedRelease = getExpandedProp(
|
||||
device.should_be_running__release,
|
||||
device.is_pinned_on__release,
|
||||
'commit',
|
||||
);
|
||||
const appSlug = getExpandedProp(device.belongs_to__application, 'slug');
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class DevicePublicUrlCmd extends Command {
|
||||
@ -56,7 +55,6 @@ export default class DevicePublicUrlCmd extends Command {
|
||||
description: 'determine if public URL is enabled',
|
||||
exclusive: ['enable', 'disable'],
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class DevicePurgeCmd extends Command {
|
||||
@ -41,10 +40,6 @@ export default class DevicePurgeCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -36,7 +36,6 @@ export default class DeviceRebootCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
force: cf.force,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
@ -50,9 +49,8 @@ export default class DeviceRegisterCmd extends Command {
|
||||
}),
|
||||
deviceType: Flags.string({
|
||||
description:
|
||||
"device type slug (run 'balena devices supported' for possible values)",
|
||||
"device type slug (run 'balena device-type list' for possible values)",
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -78,6 +76,6 @@ export default class DeviceRegisterCmd extends Command {
|
||||
options.deviceType,
|
||||
);
|
||||
|
||||
return result && result.uuid;
|
||||
return result.uuid;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
|
||||
|
||||
export default class DeviceRenameCmd extends Command {
|
||||
@ -42,10 +41,6 @@ export default class DeviceRenameCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy';
|
||||
import type {
|
||||
BalenaSDK,
|
||||
@ -58,7 +57,6 @@ export default class DeviceRestartCmd extends Command {
|
||||
'comma-separated list (no blank spaces) of service names to restart',
|
||||
char: 's',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -156,7 +154,7 @@ export default class DeviceRestartCmd extends Command {
|
||||
|
||||
async restartAllServices(balena: BalenaSDK, deviceUuid: string) {
|
||||
// Note: device.restartApplication throws `BalenaDeviceNotFound: Device not found` if device not online.
|
||||
// Need to use device.get first to distinguish between non-existant and offline devices.
|
||||
// Need to use device.get first to distinguish between non-existant and disconnected devices.
|
||||
// Remove this workaround when SDK issue resolved: https://github.com/balena-io/balena-sdk/issues/649
|
||||
const { instanceOf, ExpectedError } = await import('../../errors');
|
||||
try {
|
||||
|
@ -44,7 +44,6 @@ export default class DeviceRmCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -37,7 +37,6 @@ export default class DeviceShutdownCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
force: cf.force,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import {
|
||||
parseAsInteger,
|
||||
@ -25,6 +24,7 @@ import {
|
||||
|
||||
export default class DeviceSSHCmd extends Command {
|
||||
public static aliases = ['ssh'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Open a SSH prompt on a device's host OS or service container.
|
||||
@ -82,7 +82,7 @@ export default class DeviceSSHCmd extends Command {
|
||||
SSH server port number (default 22222) if the target is an IP address or .local
|
||||
hostname. Otherwise, port number for the balenaCloud gateway (default 22).`,
|
||||
char: 'p',
|
||||
parse: async (p) => parseAsInteger(p, 'port'),
|
||||
parse: (p) => parseAsInteger(p, 'port'),
|
||||
}),
|
||||
tty: Flags.boolean({
|
||||
default: false,
|
||||
@ -99,7 +99,6 @@ export default class DeviceSSHCmd extends Command {
|
||||
default: false,
|
||||
description: 'bypass global proxy configuration for the ssh connection',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
@ -111,13 +110,14 @@ export default class DeviceSSHCmd extends Command {
|
||||
// Local connection
|
||||
if (validateLocalHostnameOrIp(params.fleetOrDevice)) {
|
||||
const { performLocalDeviceSSH } = await import('../../utils/device/ssh');
|
||||
return await performLocalDeviceSSH({
|
||||
await performLocalDeviceSSH({
|
||||
hostname: params.fleetOrDevice,
|
||||
port: options.port || 'local',
|
||||
forceTTY: options.tty,
|
||||
verbose: options.verbose,
|
||||
service: params.service,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Remote connection
|
||||
@ -133,7 +133,7 @@ export default class DeviceSSHCmd extends Command {
|
||||
const useProxy = !!proxyConfig && !options.noproxy;
|
||||
|
||||
// this will be a tunnelled SSH connection...
|
||||
await checkNotUsingOfflineMode();
|
||||
checkNotUsingOfflineMode();
|
||||
await checkLoggedIn();
|
||||
const deviceUuid = await getOnlineTargetDeviceUuid(
|
||||
sdk,
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy';
|
||||
import type { BalenaSDK } from 'balena-sdk';
|
||||
|
||||
@ -45,10 +44,6 @@ export default class DeviceStartServiceCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy';
|
||||
import type { BalenaSDK } from 'balena-sdk';
|
||||
|
||||
@ -45,10 +44,6 @@ export default class DeviceStopServiceCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class DeviceTrackFleetCmd extends Command {
|
||||
@ -34,10 +33,6 @@ export default class DeviceTrackFleetCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -21,13 +21,15 @@ import {
|
||||
InvalidPortMappingError,
|
||||
ExpectedError,
|
||||
} from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { lowercaseIfSlug } from '../../utils/normalization';
|
||||
|
||||
import type { Server, Socket } from 'net';
|
||||
|
||||
export default class TunnelCmd extends Command {
|
||||
export default class DeviceTunnelCmd extends Command {
|
||||
public static aliases = ['tunnel'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Tunnel local ports to your balenaOS device.
|
||||
|
||||
@ -54,19 +56,19 @@ export default class TunnelCmd extends Command {
|
||||
|
||||
public static examples = [
|
||||
'# map remote port 22222 to localhost:22222',
|
||||
'$ balena tunnel myFleet -p 22222',
|
||||
'$ balena device tunnel myFleet -p 22222',
|
||||
'',
|
||||
'# map remote port 22222 to localhost:222',
|
||||
'$ balena tunnel 2ead211 -p 22222:222',
|
||||
'$ balena device tunnel 2ead211 -p 22222:222',
|
||||
'',
|
||||
'# map remote port 22222 to any address on your host machine, port 22222',
|
||||
'$ balena tunnel 1546690 -p 22222:0.0.0.0',
|
||||
'$ balena device tunnel 1546690 -p 22222:0.0.0.0',
|
||||
'',
|
||||
'# map remote port 22222 to any address on your host machine, port 222',
|
||||
'$ balena tunnel myFleet -p 22222:0.0.0.0:222',
|
||||
'$ balena device tunnel myFleet -p 22222:0.0.0.0:222',
|
||||
'',
|
||||
'# multiple port tunnels can be specified at any one time',
|
||||
'$ balena tunnel myFleet -p 8080:3000 -p 8081:9000',
|
||||
'$ balena device tunnel myFleet -p 8080:3000 -p 8081:9000',
|
||||
];
|
||||
|
||||
public static args = {
|
||||
@ -84,14 +86,13 @@ export default class TunnelCmd extends Command {
|
||||
char: 'p',
|
||||
multiple: true,
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = await this.parse(TunnelCmd);
|
||||
const { args: params, flags: options } = await this.parse(DeviceTunnelCmd);
|
||||
|
||||
const Logger = await import('../../utils/logger');
|
||||
|
2
src/commands/env/list.ts
vendored
2
src/commands/env/list.ts
vendored
@ -47,6 +47,7 @@ interface ServiceEnvironmentVariableInfo
|
||||
|
||||
export default class EnvListCmd extends Command {
|
||||
public static aliases = ['envs'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
List the environment or config variables of a fleet, device or service.
|
||||
@ -104,7 +105,6 @@ export default class EnvListCmd extends Command {
|
||||
exclusive: ['service'],
|
||||
}),
|
||||
device: { ...cf.device, exclusive: ['fleet'] },
|
||||
help: cf.help,
|
||||
json: cf.json,
|
||||
service: { ...cf.service, exclusive: ['config'] },
|
||||
};
|
||||
|
4
src/commands/env/rename.ts
vendored
4
src/commands/env/rename.ts
vendored
@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ec from '../../utils/env-common';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { parseAsInteger } from '../../utils/validation';
|
||||
@ -42,7 +41,7 @@ export default class EnvRenameCmd extends Command {
|
||||
id: Args.integer({
|
||||
required: true,
|
||||
description: "variable's numeric database ID",
|
||||
parse: async (input) => parseAsInteger(input, 'id'),
|
||||
parse: (input) => parseAsInteger(input, 'id'),
|
||||
}),
|
||||
value: Args.string({
|
||||
required: true,
|
||||
@ -55,7 +54,6 @@ export default class EnvRenameCmd extends Command {
|
||||
config: ec.booleanConfig,
|
||||
device: ec.booleanDevice,
|
||||
service: ec.booleanService,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public async run() {
|
||||
|
2
src/commands/env/rm.ts
vendored
2
src/commands/env/rm.ts
vendored
@ -46,7 +46,7 @@ export default class EnvRmCmd extends Command {
|
||||
id: Args.integer({
|
||||
required: true,
|
||||
description: "variable's numeric database ID",
|
||||
parse: async (input) => parseAsInteger(input, 'id'),
|
||||
parse: (input) => parseAsInteger(input, 'id'),
|
||||
}),
|
||||
};
|
||||
|
||||
|
3
src/commands/env/set.ts
vendored
3
src/commands/env/set.ts
vendored
@ -25,7 +25,6 @@ import { applicationIdInfo } from '../../utils/messages';
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
device?: string; // device UUID
|
||||
help: void;
|
||||
quiet: boolean;
|
||||
service?: string; // service name
|
||||
}
|
||||
@ -37,6 +36,7 @@ interface ArgsDef {
|
||||
|
||||
export default class EnvSetCmd extends Command {
|
||||
public static aliases = ['env add'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Add or update env or config variable to fleets, devices or services.
|
||||
@ -97,7 +97,6 @@ export default class EnvSetCmd extends Command {
|
||||
public static flags = {
|
||||
fleet: { ...cf.fleet, exclusive: ['device'] },
|
||||
device: { ...cf.device, exclusive: ['fleet'] },
|
||||
help: cf.help,
|
||||
quiet: cf.quiet,
|
||||
service: cf.service,
|
||||
};
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class FleetCreateCmd extends Command {
|
||||
@ -31,7 +30,7 @@ export default class FleetCreateCmd extends Command {
|
||||
\`balena organization list\` command.
|
||||
|
||||
The fleet's default device type is specified with the \`--type\` option.
|
||||
The \`balena devices supported\` command can be used to list the available
|
||||
The \`balena device-type list\` command can be used to list the available
|
||||
device types.
|
||||
|
||||
Interactive dropdowns will be shown for selection if no device type or
|
||||
@ -62,9 +61,8 @@ export default class FleetCreateCmd extends Command {
|
||||
type: Flags.string({
|
||||
char: 't',
|
||||
description:
|
||||
'fleet device type (Check available types with `balena devices supported`)',
|
||||
'fleet device type (Check available types with `balena device-type list`)',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -40,7 +40,6 @@ export default class FleetCmd extends Command {
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
view: Flags.boolean({
|
||||
default: false,
|
||||
description: 'open fleet dashboard page',
|
||||
|
@ -28,6 +28,7 @@ interface ExtendedApplication extends ApplicationWithDeviceTypeSlug {
|
||||
|
||||
export default class FleetListCmd extends Command {
|
||||
public static aliases = ['fleets'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
List all fleets.
|
||||
@ -41,7 +42,6 @@ export default class FleetListCmd extends Command {
|
||||
public static examples = ['$ balena fleet list'];
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
json: cf.json,
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { getExpandedProp } from '../../utils/pine';
|
||||
|
||||
@ -43,10 +42,6 @@ export default class FleetPinCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
@ -40,10 +39,6 @@ export default class FleetPurgeCmd extends Command {
|
||||
fleet: ca.fleetRequired,
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
@ -46,10 +45,6 @@ export default class FleetRenameCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import * as ca from '../../utils/common-args';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
@ -39,10 +38,6 @@ export default class FleetRestartCmd extends Command {
|
||||
fleet: ca.fleetRequired,
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -44,7 +44,6 @@ export default class FleetRmCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class FleetTrackLatestCmd extends Command {
|
||||
@ -37,10 +36,6 @@ export default class FleetTrackLatestCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -65,7 +65,6 @@ export default class JoinCmd extends Command {
|
||||
description: 'the interval in minutes to check for updates',
|
||||
char: 'i',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
import { parseAsLocalHostnameOrIp } from '../../utils/validation';
|
||||
|
||||
@ -49,10 +48,6 @@ export default class LeaveCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
public static primary = true;
|
||||
|
||||
|
@ -16,8 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import { promisify } from 'util';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class LocalConfigureCmd extends Command {
|
||||
@ -39,10 +37,6 @@ export default class LocalConfigureCmd extends Command {
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static root = true;
|
||||
public static offlineCompatible = true;
|
||||
|
||||
@ -242,7 +236,7 @@ export default class LocalConfigureCmd extends Command {
|
||||
const bootPartition = await getBootPartition(target);
|
||||
|
||||
const files = await imagefs.interact(target, bootPartition, async (_fs) => {
|
||||
return await promisify(_fs.readdir)(this.CONNECTIONS_FOLDER);
|
||||
return await _fs.promises.readdir(this.CONNECTIONS_FOLDER);
|
||||
});
|
||||
|
||||
let connectionFileName;
|
||||
@ -251,13 +245,11 @@ export default class LocalConfigureCmd extends Command {
|
||||
} else if (_.includes(files, 'resin-sample.ignore')) {
|
||||
// Fresh image, new mode, accoding to https://github.com/balena-os/meta-balena/pull/770/files
|
||||
await imagefs.interact(target, bootPartition, async (_fs) => {
|
||||
const readFileAsync = promisify(_fs.readFile);
|
||||
const writeFileAsync = promisify(_fs.writeFile);
|
||||
const contents = await readFileAsync(
|
||||
const contents = await _fs.promises.readFile(
|
||||
`${this.CONNECTIONS_FOLDER}/resin-sample.ignore`,
|
||||
{ encoding: 'utf8' },
|
||||
);
|
||||
return await writeFileAsync(
|
||||
await _fs.promises.writeFile(
|
||||
`${this.CONNECTIONS_FOLDER}/resin-wifi`,
|
||||
contents,
|
||||
);
|
||||
@ -274,13 +266,13 @@ export default class LocalConfigureCmd extends Command {
|
||||
} else {
|
||||
// In case there's no file at all (shouldn't happen normally, but the file might have been removed)
|
||||
await imagefs.interact(target, bootPartition, async (_fs) => {
|
||||
return await promisify(_fs.writeFile)(
|
||||
await _fs.promises.writeFile(
|
||||
`${this.CONNECTIONS_FOLDER}/resin-wifi`,
|
||||
this.CONNECTION_FILE,
|
||||
);
|
||||
});
|
||||
}
|
||||
return await this.getConfigurationSchema(bootPartition, connectionFileName);
|
||||
return this.getConfigurationSchema(bootPartition, connectionFileName);
|
||||
}
|
||||
|
||||
async removeHostname(schema: any) {
|
||||
|
@ -48,7 +48,6 @@ export default class LocalFlashCmd extends Command {
|
||||
public static flags = {
|
||||
drive: cf.drive,
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static offlineCompatible = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import type { WhoamiResult } from 'balena-sdk';
|
||||
@ -29,7 +28,6 @@ interface FlagsDef {
|
||||
user?: string;
|
||||
password?: string;
|
||||
port?: number;
|
||||
help: void;
|
||||
hideExperimentalWarning: boolean;
|
||||
}
|
||||
|
||||
@ -111,7 +109,6 @@ export default class LoginCmd extends Command {
|
||||
default: false,
|
||||
description: 'Hides warning for experimental features',
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
@ -135,7 +132,7 @@ export default class LoginCmd extends Command {
|
||||
// We can safely assume this won't be undefined as doLogin will throw if this call fails
|
||||
// We also don't need to worry too much about the amount of calls to whoami
|
||||
// as these are cached by the SDK
|
||||
const whoamiResult = (await balena.auth.whoami()) as WhoamiResult;
|
||||
const whoamiResult = (await balena.auth.whoami())!;
|
||||
|
||||
if (whoamiResult.actorType !== 'user' && !options.hideExperimentalWarning) {
|
||||
console.info(stripIndent`
|
||||
@ -171,7 +168,7 @@ ${messages.reachingOut}`);
|
||||
|
||||
async doLogin(
|
||||
loginOptions: FlagsDef,
|
||||
balenaUrl: string = 'balena-cloud.com',
|
||||
balenaUrl = 'balena-cloud.com',
|
||||
token?: string,
|
||||
): Promise<void> {
|
||||
// Token
|
||||
|
@ -16,11 +16,11 @@
|
||||
*/
|
||||
|
||||
import { Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class OrganizationListCmd extends Command {
|
||||
public static aliases = ['orgs'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
List all organizations.
|
||||
@ -29,10 +29,6 @@ export default class OrganizationListCmd extends Command {
|
||||
`;
|
||||
public static examples = ['$ balena organization list'];
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getCliForm, stripIndent } from '../../utils/lazy';
|
||||
import * as _ from 'lodash';
|
||||
import type { DeviceTypeJson } from 'balena-sdk';
|
||||
@ -55,7 +54,6 @@ export default class OsBuildConfigCmd extends Command {
|
||||
char: 'o',
|
||||
required: true,
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -18,7 +18,6 @@
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import type { Interfaces } from '@oclif/core';
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
import { promisify } from 'util';
|
||||
import * as _ from 'lodash';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
@ -154,7 +153,6 @@ export default class OsConfigureCmd extends Command {
|
||||
'expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)',
|
||||
exclusive: ['config', 'device'],
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -293,7 +291,7 @@ export default class OsConfigureCmd extends Command {
|
||||
|
||||
for (const { name, content } of files) {
|
||||
await imagefs.interact(image, bootPartition, async (_fs) => {
|
||||
return await promisify(_fs.writeFile)(
|
||||
await _fs.promises.writeFile(
|
||||
path.join(CONNECTIONS_FOLDER, name),
|
||||
content,
|
||||
);
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class OsDownloadCmd extends Command {
|
||||
@ -24,7 +23,7 @@ export default class OsDownloadCmd extends Command {
|
||||
Download an unconfigured OS image.
|
||||
|
||||
Download an unconfigured OS image for the specified device type.
|
||||
Check available device types with 'balena devices supported'.
|
||||
Check available device types with 'balena device-type list'.
|
||||
|
||||
Note: Currently this command only works with balenaCloud, not openBalena.
|
||||
If using openBalena, please download the OS from: https://www.balena.io/os/
|
||||
@ -78,7 +77,6 @@ export default class OsDownloadCmd extends Command {
|
||||
or 'menu-esr' (interactive menu, ESR versions)
|
||||
`,
|
||||
}),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public async run() {
|
||||
|
@ -51,7 +51,6 @@ export default class OsInitializeCmd extends Command {
|
||||
type: cf.deviceType,
|
||||
drive: cf.drive,
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class OsVersionsCmd extends Command {
|
||||
@ -24,7 +23,7 @@ export default class OsVersionsCmd extends Command {
|
||||
Show available balenaOS versions for the given device type.
|
||||
|
||||
Show the available balenaOS versions for the given device type.
|
||||
Check available types with \`balena devices supported\`.
|
||||
Check available types with \`balena device-type list\`.
|
||||
|
||||
balenaOS ESR versions can be listed with the '--esr' option. See also:
|
||||
https://www.balena.io/docs/reference/OS/extended-support-release/
|
||||
@ -40,7 +39,6 @@ export default class OsVersionsCmd extends Command {
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
esr: Flags.boolean({
|
||||
description: 'select balenaOS ESR versions',
|
||||
default: false,
|
||||
|
@ -37,6 +37,7 @@ import type {
|
||||
Release,
|
||||
} from 'balena-sdk';
|
||||
import type { Preloader } from 'balena-preload';
|
||||
import type * as Fs from 'fs';
|
||||
|
||||
export default class PreloadCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
@ -84,9 +85,9 @@ export default class PreloadCmd extends Command {
|
||||
description: `\
|
||||
The commit hash of the release to preload. Use "current" to specify the current
|
||||
release (ignored if no appId is given). The current release is usually also the
|
||||
latest, but can be pinned to a specific release. See:
|
||||
https://www.balena.io/docs/learn/deploy/release-strategy/release-policy/
|
||||
https://www.balena.io/docs/learn/more/masterclasses/fleet-management/#63-pin-using-the-api
|
||||
latest, but can be pinned to a specific release. See:
|
||||
https://www.balena.io/docs/learn/deploy/release-strategy/release-policy/
|
||||
https://www.balena.io/docs/learn/more/masterclasses/fleet-management/#63-pin-using-the-api
|
||||
https://github.com/balena-io-examples/staged-releases\
|
||||
`,
|
||||
char: 'c',
|
||||
@ -109,7 +110,7 @@ https://github.com/balena-io-examples/staged-releases\
|
||||
'additional-space': Flags.integer({
|
||||
description:
|
||||
'expand the image by this amount of bytes instead of automatically estimating the required amount',
|
||||
parse: async (x) => parseAsInteger(x, 'additional-space'),
|
||||
parse: (x) => parseAsInteger(x, 'additional-space'),
|
||||
}),
|
||||
'add-certificate': Flags.string({
|
||||
description: `\
|
||||
@ -126,11 +127,8 @@ Can be repeated to add multiple certificates.\
|
||||
dockerPort: Flags.integer({
|
||||
description:
|
||||
'Docker daemon TCP port number (hint: 2375 for balena devices)',
|
||||
parse: async (p) => parseAsInteger(p, 'dockerPort'),
|
||||
parse: (p) => parseAsInteger(p, 'dockerPort'),
|
||||
}),
|
||||
// Not supporting -h for help, because of clash with -h in DockerCliFlags
|
||||
// Revisit this in future release.
|
||||
help: Flags.help({}),
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
@ -158,12 +156,48 @@ Can be repeated to add multiple certificates.\
|
||||
------------------------------------------------------------------------------
|
||||
`);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
throw new ExpectedError(
|
||||
`The provided image path does not exist: ${params.image}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Verify that image is not enabled for secure boot. First, confirm it is
|
||||
// a secure boot image with a .sig file in the /opt directory of the rootA
|
||||
// partition. For example, below are contents for generic-amd64 device type:
|
||||
// $ ls -l opt
|
||||
// total 864696
|
||||
// -rw-r--r-- 1 root root 2378170368 Mar 26 09:14 balena-image-generic-amd64.balenaos-img
|
||||
// -rw-r--r-- 1 root root 512 Mar 9 2018 balena-image-generic-amd64.balenaos-img.sig
|
||||
const { explorePartition, BalenaPartition } = await import(
|
||||
'../../utils/image-contents'
|
||||
);
|
||||
const isSecureBoot = await explorePartition<boolean>(
|
||||
params.image,
|
||||
BalenaPartition.ROOTA,
|
||||
async (fs: typeof Fs): Promise<boolean> => {
|
||||
try {
|
||||
const files = await fs.promises.readdir('/opt');
|
||||
return files.some((el) => el.endsWith('balenaos-img.sig'));
|
||||
} catch {
|
||||
// Typically one of:
|
||||
// - Error: No such file or directory
|
||||
// - Error: Unsupported filesystem.
|
||||
// - ErrnoException: node_ext2fs_open ENOENT (44) args: [5261576,5268064,"r",0]
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
);
|
||||
// Next verify that config.json enables secureboot.
|
||||
if (isSecureBoot) {
|
||||
const { read } = await import('balena-config-json');
|
||||
const config = await read(params.image, '');
|
||||
if (config.installer?.secureboot === true) {
|
||||
throw new ExpectedError("Can't preload image with secure boot enabled");
|
||||
}
|
||||
}
|
||||
|
||||
// balena-preload currently does not work with numerical app IDs
|
||||
// Load app here, and use app slug from hereon
|
||||
const fleetSlug: string | undefined = options.fleet
|
||||
@ -195,11 +229,11 @@ Can be repeated to add multiple certificates.\
|
||||
event.name,
|
||||
));
|
||||
if (event.action === 'start') {
|
||||
return spinner.start();
|
||||
} else {
|
||||
console.log();
|
||||
return spinner.stop();
|
||||
spinner.start();
|
||||
return;
|
||||
}
|
||||
console.log();
|
||||
spinner.stop();
|
||||
};
|
||||
|
||||
const commit = this.isCurrentCommit(options.commit || '')
|
||||
@ -298,7 +332,7 @@ Can be repeated to add multiple certificates.\
|
||||
owns__release: {
|
||||
$select: ['id', 'commit', 'end_timestamp', 'composition'],
|
||||
$expand: {
|
||||
contains__image: {
|
||||
release_image: {
|
||||
$select: ['image'],
|
||||
$expand: {
|
||||
image: {
|
||||
@ -413,6 +447,8 @@ Can be repeated to add multiple certificates.\
|
||||
const DEFAULT_CHOICE = { name: 'current', value: 'current' };
|
||||
const choices = [DEFAULT_CHOICE].concat(
|
||||
releases.map((release) => ({
|
||||
// TODO: [next-major] consider changing this to use the release semver
|
||||
// and maybe the commit as well
|
||||
name: `${release.end_timestamp} - ${release.commit}`,
|
||||
value: release.commit,
|
||||
})),
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import type { Interfaces } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { dockerignoreHelp, registrySecretsHelp } from '../../utils/messages';
|
||||
import type { BalenaSDK } from 'balena-sdk';
|
||||
@ -218,7 +217,6 @@ export default class PushCmd extends Command {
|
||||
default: false,
|
||||
}),
|
||||
note: Flags.string({ description: 'The notes for this release' }),
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static primary = true;
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
import { Command } from '@oclif/core';
|
||||
import { commitOrIdArg } from '.';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class ReleaseFinalizeCmd extends Command {
|
||||
@ -40,10 +39,6 @@ export default class ReleaseFinalizeCmd extends Command {
|
||||
'$ balena release finalize 1234567',
|
||||
];
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static args = {
|
||||
commitOrId: commitOrIdArg({
|
||||
description: 'the commit or ID of the release to finalize',
|
||||
|
@ -24,7 +24,7 @@ import { tryAsInteger } from '../../utils/validation';
|
||||
import { jsonInfo } from '../../utils/messages';
|
||||
|
||||
export const commitOrIdArg = Args.custom({
|
||||
parse: async (commitOrId: string) => tryAsInteger(commitOrId),
|
||||
parse: tryAsInteger,
|
||||
});
|
||||
|
||||
type FlagsDef = Interfaces.InferredFlags<typeof ReleaseCmd.flags>;
|
||||
@ -43,7 +43,6 @@ export default class ReleaseCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
json: cf.json,
|
||||
help: cf.help,
|
||||
composition: Flags.boolean({
|
||||
default: false,
|
||||
char: 'c',
|
||||
@ -87,7 +86,7 @@ export default class ReleaseCmd extends Command {
|
||||
balena: BalenaSdk.BalenaSDK,
|
||||
options: FlagsDef,
|
||||
) {
|
||||
const fields: Array<keyof BalenaSdk.Release> = [
|
||||
const fields = [
|
||||
'id',
|
||||
'commit',
|
||||
'created_at',
|
||||
@ -97,7 +96,7 @@ export default class ReleaseCmd extends Command {
|
||||
'build_log',
|
||||
'start_timestamp',
|
||||
'end_timestamp',
|
||||
];
|
||||
] satisfies BalenaSdk.PineOptions<BalenaSdk.Release>['$select'];
|
||||
|
||||
const release = await balena.models.release.get(commitOrId, {
|
||||
...(!options.json && { $select: fields }),
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
import { Command } from '@oclif/core';
|
||||
import { commitOrIdArg } from '.';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class ReleaseInvalidateCmd extends Command {
|
||||
@ -35,10 +34,6 @@ export default class ReleaseInvalidateCmd extends Command {
|
||||
'$ balena release invalidate 1234567',
|
||||
];
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static args = {
|
||||
commitOrId: commitOrIdArg({
|
||||
description: 'the commit or ID of the release to invalidate',
|
||||
|
@ -24,6 +24,7 @@ import { jsonInfo } from '../../utils/messages';
|
||||
|
||||
export default class ReleaseListCmd extends Command {
|
||||
public static aliases = ['releases'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
List all releases of a fleet.
|
||||
@ -41,7 +42,6 @@ export default class ReleaseListCmd extends Command {
|
||||
|
||||
public static flags = {
|
||||
json: cf.json,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static args = {
|
||||
@ -56,14 +56,14 @@ export default class ReleaseListCmd extends Command {
|
||||
public async run() {
|
||||
const { args: params, flags: options } = await this.parse(ReleaseListCmd);
|
||||
|
||||
const fields: Array<keyof BalenaSdk.Release> = [
|
||||
const fields = [
|
||||
'id',
|
||||
'commit',
|
||||
'created_at',
|
||||
'status',
|
||||
'semver',
|
||||
'is_final',
|
||||
];
|
||||
] satisfies BalenaSdk.PineOptions<BalenaSdk.Release>['$select'];
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const { getFleetSlug } = await import('../../utils/sdk');
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
import { Command } from '@oclif/core';
|
||||
import { commitOrIdArg } from '.';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class ReleaseValidateCmd extends Command {
|
||||
@ -34,10 +33,6 @@ export default class ReleaseValidateCmd extends Command {
|
||||
'$ balena release validate 1234567',
|
||||
];
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static args = {
|
||||
commitOrId: commitOrIdArg({
|
||||
description: 'the commit or ID of the release to validate',
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class SettingsCmd extends Command {
|
||||
@ -27,10 +26,6 @@ export default class SettingsCmd extends Command {
|
||||
`;
|
||||
public static examples = ['$ balena settings'];
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public async run() {
|
||||
await this.parse(SettingsCmd);
|
||||
|
||||
|
@ -16,12 +16,11 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class SSHKeyAddCmd extends Command {
|
||||
public static aliases = ['key add'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Add an SSH key to balenaCloud.
|
||||
@ -59,24 +58,21 @@ export default class SSHKeyAddCmd extends Command {
|
||||
}),
|
||||
path: Args.string({
|
||||
description: `the path to the public key file`,
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = await this.parse(SSHKeyAddCmd);
|
||||
|
||||
const { readFile } = (await import('fs')).promises;
|
||||
let key: string;
|
||||
if (params.path != null) {
|
||||
const { readFile } = (await import('fs')).promises;
|
||||
try {
|
||||
key = await readFile(params.path, 'utf8');
|
||||
} else {
|
||||
throw new ExpectedError('No public key file or path provided.');
|
||||
} catch {
|
||||
key = params.path;
|
||||
}
|
||||
|
||||
await getBalenaSdk().models.key.create(params.name, key);
|
||||
|
@ -16,12 +16,12 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
import { parseAsInteger } from '../../utils/validation';
|
||||
|
||||
export default class SSHKeyCmd extends Command {
|
||||
public static aliases = ['key'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Display an SSH key.
|
||||
@ -34,15 +34,11 @@ export default class SSHKeyCmd extends Command {
|
||||
public static args = {
|
||||
id: Args.integer({
|
||||
description: 'balenaCloud ID for the SSH key',
|
||||
parse: async (x) => parseAsInteger(x, 'id'),
|
||||
parse: (x) => parseAsInteger(x, 'id'),
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -16,11 +16,11 @@
|
||||
*/
|
||||
|
||||
import { Command } from '@oclif/core';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class SSHKeyListCmd extends Command {
|
||||
public static aliases = ['keys', 'key list'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
List the SSH keys in balenaCloud.
|
||||
@ -29,10 +29,6 @@ export default class SSHKeyListCmd extends Command {
|
||||
`;
|
||||
public static examples = ['$ balena ssh-key list'];
|
||||
|
||||
public static flags = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
|
@ -22,6 +22,7 @@ import { parseAsInteger } from '../../utils/validation';
|
||||
|
||||
export default class SSHKeyRmCmd extends Command {
|
||||
public static aliases = ['key rm'];
|
||||
public static deprecateAliases = true;
|
||||
|
||||
public static description = stripIndent`
|
||||
Remove an SSH key from balenaCloud.
|
||||
@ -39,14 +40,13 @@ export default class SSHKeyRmCmd extends Command {
|
||||
public static args = {
|
||||
id: Args.integer({
|
||||
description: 'balenaCloud ID for the SSH key',
|
||||
parse: async (x) => parseAsInteger(x, 'id'),
|
||||
parse: (x) => parseAsInteger(x, 'id'),
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
||||
public static flags = {
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user