Compare commits

...

22 Commits

Author SHA1 Message Date
237a0a621e Update npm-shrinkwrap 2025-01-06 15:06:40 -03:00
a1952bf347 Enable dual stack support for balena tunnel
The `balena tunnel`commands uses `localhost` as the default listening
address. The problem is that on some dual stack networks (IPv4/IPv6),
this can result on the tunneling server only binding to `::1` and not
to `127.0.0.1`, potentially causing issues as this behavior is not
intuitive.

This PR replaces the default server name with `::` which setups the
server in dual-stack mode.

Change-type: patch
2025-01-06 15:01:00 -03:00
017c767f61 v20.2.1 2025-01-01 18:05:02 +00:00
7d79c4e24b Merge pull request #2905 from balena-io/update-balena-preload-17.0.0
Update balena-preload to 17.0.0
2025-01-01 20:04:01 +02:00
60bc5092e0 Update balena-preload to 17.0.0
Update balena-preload from 16.0.0 to 17.0.0

Change-type: patch
2024-12-31 20:42:54 +02:00
a33a794931 v20.2.0 2024-12-31 18:41:50 +00:00
f0ede6fca2 Merge pull request #2901 from balena-io/balena-device-init-v-8-1-0
os configure: Locate the boot partition w/o using the device-type.json's partition field
2024-12-31 10:40:54 -08:00
dbe177e766 os configure: Give precedence to the boot partition located in the image over the device-type.json contents
Update balena-device-init from 8.0.0 to 8.1.0

Change-type: minor
2024-12-31 19:48:11 +02:00
09f80730a8 Deduplicate dependencies 2024-12-31 19:47:11 +02:00
327d28c103 v20.1.6 2024-12-30 17:16:14 +00:00
56ab785a82 Merge pull request #2903 from balena-io/os-configure-tests
Add more realistic os configure tests
2024-12-30 17:15:09 +00:00
305d65d5ed Add more realistic os configure tests
Change-type: patch
2024-12-30 18:44:07 +02:00
c4d3686a34 Deduplicate dependencies 2024-12-30 15:57:12 +02:00
ce06854b55 v20.1.5 2024-12-20 17:55:24 +00:00
8db05cc8a7 Merge pull request #2902 from oskarwilliams/express-version-4.21.2
Update shrinkwrapped express to v4.21.2
2024-12-20 17:54:36 +00:00
7a22c987d2 Update shrinkwrapped express to v4.21.2
Change-type: patch
2024-12-20 17:23:28 +00:00
45efbcdfe3 v20.1.4 2024-12-20 16:57:38 +00:00
d6a9b78b3e Merge pull request #2899 from balena-io/balena-device-init-v8
Update balena-device-init to 8.0.0
2024-12-20 16:56:43 +00:00
e8ac3ea960 Update balena-device-init to 8.0.0
Update balena-device-init from 7.0.1 to 8.0.0

Change-type: patch
See: https://github.com/balena-io-modules/balena-device-init/pull/46
2024-12-20 18:36:50 +02:00
0ffa0f85a2 v20.1.3 2024-12-20 14:33:05 +00:00
5e7479f60e Merge pull request #2898 from balena-io/bump-oclif-and-oclif-core
Update oclif to 4.17.0 and @oclif/core 4.1.0
2024-12-20 11:32:01 -03:00
07365c45f2 Update oclif to 4.17.0 and @oclif/core 4.1.0
Change-type: patch
2024-12-20 11:09:29 -03:00
13 changed files with 2687 additions and 959 deletions

View File

@ -1,3 +1,208 @@
- commits:
- subject: Update balena-preload to 17.0.0
hash: 60bc5092e0d6014aecf57d157cac536b3c645f0f
body: |
Update balena-preload from 16.0.0 to 17.0.0
footer:
Change-type: patch
change-type: patch
author: Thodoris Greasidis
nested:
- commits:
- subject: Improve typings
hash: 67f0f3e9e3b4b37fbaeef2843dc4171a7d661c41
body: ""
footer:
Change-type: patch
change-type: patch
author: Thodoris Greasidis
nested: []
- subject: Stop returning Bluebird promises & drop it from the dependencies
hash: 85375cbc1fdb0ce1ad08756f178ed55596e606d9
body: ""
footer:
Change-type: major
change-type: major
author: Thodoris Greasidis
nested: []
version: balena-preload-17.0.0
title: ""
date: 2024-10-21T16:20:33.486Z
version: 20.2.1
title: ""
date: 2025-01-01T18:04:56.723Z
- commits:
- subject: "os configure: Give precedence to the boot partition located in the
image over the device-type.json contents"
hash: dbe177e76639040c5fac49746fbbcee2e3360d0a
body: |
Update balena-device-init from 8.0.0 to 8.1.0
footer:
Change-type: minor
change-type: minor
author: Thodoris Greasidis
nested:
- commits:
- subject: Try to find the boot partition by inspecting the image
hash: de53f11c56133bf2757c5361f8dbc6afa9e826fc
body: ""
footer:
Change-type: minor
change-type: minor
author: Thodoris Greasidis
nested: []
version: balena-device-init-8.1.0
title: ""
date: 2024-12-30T12:41:49.474Z
- commits:
- subject: Drop the unnecessary eslint.config.js
hash: 91d587f34bf985bf65e6c21278e7cd70f9281656
body: ""
footer:
Change-type: patch
change-type: patch
author: Thodoris Greasidis
nested: []
- subject: "packacke.json: Explicitly set type commonjs"
hash: f6a0be1d12f09d7d910e5ae35f48f1268542a74e
body: ""
footer:
Change-type: patch
change-type: patch
author: Thodoris Greasidis
nested: []
version: balena-device-init-8.0.1
title: ""
date: 2024-12-19T13:41:14.170Z
version: 20.2.0
title: ""
date: 2024-12-31T18:41:45.907Z
- commits:
- subject: Add more realistic os configure tests
hash: 305d65d5ed07cce767599ac4e5dd131e2a87d10d
body: ""
footer:
Change-type: patch
change-type: patch
author: Thodoris Greasidis
nested: []
version: 20.1.6
title: ""
date: 2024-12-30T17:16:09.432Z
- commits:
- subject: Update shrinkwrapped express to v4.21.2
hash: 7a22c987d24aca0754bde5618c232424ede72656
body: ""
footer:
Change-type: patch
change-type: patch
author: Oskar Williams
nested: []
version: 20.1.5
title: ""
date: 2024-12-20T17:55:20.670Z
- commits:
- subject: Update balena-device-init to 8.0.0
hash: e8ac3ea960b1765470b496dbd714036d9b2ecd93
body: |
Update balena-device-init from 7.0.1 to 8.0.0
footer:
Change-type: patch
change-type: patch
See: https://github.com/balena-io-modules/balena-device-init/pull/46
see: https://github.com/balena-io-modules/balena-device-init/pull/46
author: Thodoris Greasidis
nested:
- commits:
- subject: Avoid running linting in the custom tests
hash: 420f93d5b2c60b67157897d8bbe0fab315c98b54
body: |
Balena-lint for some reason was failing in the
windows custom test runner.
footer:
Change-type: patch
change-type: patch
author: Thodoris Greasidis
nested: []
- subject: Stop returning Bluebird promises
hash: b76200a113fee69e11bf182945c382081f8d25e1
body: ""
footer:
Change-type: major
change-type: major
author: Thodoris Greasidis
nested: []
- subject: "package: Publish only the build & typings folders"
hash: d1754650272913577b3ce0786941ad54d4acddc8
body: ""
footer:
Change-type: major
change-type: major
author: Thodoris Greasidis
nested: []
- subject: Convert to TypeScript with es6 module notation
hash: 3576d2c423b294a8703f5474f72a9b906cef927a
body: ""
footer:
Change-type: major
change-type: major
author: Thodoris Greasidis
nested: []
- subject: Replace gulp, coffeelint & mochainon with tsc, @balena/lint, mocha,
chai & sinon
hash: 4c0cf8af370962e8eefda3a2855113629c4ffbb5
body: ""
footer:
Change-type: patch
change-type: patch
author: Thodoris Greasidis
nested: []
- subject: Drop support for node <20.6.0
hash: b7c76be409a7a691db66466bc6d6eb746c0ca51e
body: ""
footer:
Change-type: major
change-type: major
author: Thodoris Greasidis
nested: []
version: balena-device-init-8.0.0
title: ""
date: 2024-12-18T17:01:33.082Z
- commits:
- subject: "flowzone: Update runner versions"
hash: ba1222ac43ca13b720b64d18129193be8b99af5b
body: ""
footer:
Change-type: patch
change-type: patch
author: Thodoris Greasidis
nested: []
- subject: Pin etcher-sdk to 9.0.8 to match resin-device-operations and fix tests
hash: 65cde1b940b7bdcc64d34534afa4d9b7b1d14303
body: ""
footer:
Change-type: patch
change-type: patch
author: Thodoris Greasidis
nested: []
version: balena-device-init-7.0.2
title: ""
date: 2024-12-17T20:16:06.532Z
version: 20.1.4
title: ""
date: 2024-12-20T16:57:31.612Z
- commits:
- subject: Update oclif to 4.17.0 and @oclif/core 4.1.0
hash: 07365c45f2d9a46094faa60d62395c4ba139c9f6
body: ""
footer:
Change-type: patch
change-type: patch
author: Otavio Jacobi
nested: []
version: 20.1.3
title: ""
date: 2024-12-20T14:32:59.953Z
- commits:
- subject: Remove unnecessary `Promise.resolve` and `Promise.reject`
hash: e192767156ef7123be76fb838b8cf1a4d80aeb54

View File

@ -4,6 +4,73 @@ 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/).
## 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]

2986
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "balena-cli",
"version": "20.1.2",
"version": "20.2.1",
"description": "The official balena Command Line Interface",
"main": "./build/app.js",
"homepage": "https://github.com/balena-io/balena-cli",
@ -180,7 +180,7 @@
"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",
@ -193,13 +193,13 @@
"@balena/dockerignore": "^1.0.2",
"@balena/env-parsing": "^1.1.8",
"@balena/es-version": "^1.0.1",
"@oclif/core": "^4.0.31",
"@oclif/core": "^4.1.0",
"@sentry/node": "^6.16.1",
"balena-config-json": "^4.2.0",
"balena-device-init": "^7.0.1",
"balena-device-init": "^8.1.0",
"balena-errors": "^4.7.3",
"balena-image-fs": "^7.0.6",
"balena-preload": "^16.0.0",
"balena-preload": "^17.0.0",
"balena-sdk": "^20.8.0",
"balena-semver": "^2.3.0",
"balena-settings-client": "^5.0.2",
@ -274,6 +274,6 @@
}
},
"versionist": {
"publishedAt": "2024-12-17T11:34:56.167Z"
"publishedAt": "2025-01-01T18:04:59.323Z"
}
}

View File

@ -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')) {

View File

@ -6,6 +6,8 @@ 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-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'

View File

@ -203,7 +203,7 @@ export default class DeviceTunnelCmd extends Command {
parsePortMapping(portMapping: string) {
const mappingElements = portMapping.split(':');
let localAddress = 'localhost';
let localAddress = '::';
// First element is always remotePort
// TODO: figure out why we have explicitly passed `undefined` for the radix parameter

View File

@ -110,6 +110,27 @@ export async function getManifest(
const init = await import('balena-device-init');
const sdk = getBalenaSdk();
const manifest = await init.getImageManifest(image);
if (manifest != null) {
const config = manifest.configuration?.config;
if (config?.partition != null) {
const { getBootPartition } = await import('balena-config-json');
// Find the device-type.json property that holds the boot partition number for
// this device type (config.partition or config.partition.primary) and overwrite it
// with the boot partition number that was found by inspecting the image.
// since it's deprecated & no longer updated for newer releases.
if (typeof config.partition === 'number') {
config.partition = await getBootPartition(image);
} else if (config.partition.primary != null) {
config.partition.primary = await getBootPartition(image);
}
// TODO: Add handling for when we no longer include a `config.partition` at all.
}
} else {
// TODO: Change this in the next major to throw, after confirming that this works for all supported OS versions.
console.error(
`[warn] Error while finding a device-type.json on the provided image path. Attempting to fetch from the API.`,
);
}
if (
manifest != null &&
manifest.slug !== deviceType &&

View File

@ -21,6 +21,8 @@ import * as process from 'process';
import { runCommand } from '../../helpers';
import { promisify } from 'util';
import * as tmp from 'tmp';
import type * as $imagefs from 'balena-image-fs';
import * as stripIndent from 'common-tags/lib/stripIndent';
tmp.setGracefulCleanup();
const tmpNameAsync = promisify(tmp.tmpName);
@ -29,30 +31,92 @@ import { BalenaAPIMock } from '../../nock/balena-api-mock';
if (process.platform !== 'win32') {
describe('balena os configure', function () {
let imagefs: typeof $imagefs;
let api: BalenaAPIMock;
let tmpPath: string;
let tmpDummyPath: string;
let tmpMatchingDtJsonPartitionPath: string;
let tmpNonMatchingDtJsonPartitionPath: string;
beforeEach(async () => {
before(async function () {
// We conditionally import balena-image-fs, since when imported on top level then unrelated tests on win32 failed with:
// EPERM: operation not permitted, rename 'C:\Users\RUNNER~1\AppData\Local\Temp\tmp-<...>.inprogress' -> 'C:\Users\RUNNER~1\AppData\Local\Temp\tmp-<...>'
// at async Object.rename (node:internal/fs/promises:782:10) {
imagefs = await import('balena-image-fs');
tmpDummyPath = (await tmpNameAsync()) as string;
await fs.copyFile('./tests/test-data/dummy.img', tmpDummyPath);
tmpMatchingDtJsonPartitionPath = (await tmpNameAsync()) as string;
await fs.copyFile(
'./tests/test-data/mock-jetson-nano-6.0.13.with-boot-partition-12.img',
tmpMatchingDtJsonPartitionPath,
);
tmpNonMatchingDtJsonPartitionPath = (await tmpNameAsync()) as string;
// Create an image with a device-type.json that mentions a non matching boot partition.
// We copy the pre-existing image and modify it, since including a separate one
// would add 18MB more to the repository.
await fs.copyFile(
'./tests/test-data/mock-jetson-nano-6.0.13.with-boot-partition-12.img',
tmpNonMatchingDtJsonPartitionPath,
);
await imagefs.interact(
tmpNonMatchingDtJsonPartitionPath,
12,
async (_fs) => {
const readFileAsync = promisify(_fs.readFile);
const writeFileAsync = promisify(_fs.writeFile);
const dtJson = JSON.parse(
await readFileAsync('/device-type.json', { encoding: 'utf8' }),
);
expect(dtJson).to.have.nested.property(
'configuration.config.partition',
12,
);
dtJson.configuration.config.partition = 999;
await writeFileAsync('/device-type.json', JSON.stringify(dtJson));
await writeFileAsync(
'/os-release',
stripIndent`
ID="balena-os"
NAME="balenaOS"
VERSION="6.1.25"
VERSION_ID="6.1.25"
PRETTY_NAME="balenaOS 6.1.25"
DISTRO_CODENAME="kirkstone"
MACHINE="jetson-nano"
META_BALENA_VERSION="6.1.25"`,
);
},
);
});
beforeEach(() => {
api = new BalenaAPIMock();
api.expectGetWhoAmI({ optional: true, persist: true });
tmpPath = (await tmpNameAsync()) as string;
await fs.copyFile('./tests/test-data/dummy.img', tmpPath);
});
afterEach(async () => {
afterEach(() => {
api.done();
await fs.unlink(tmpPath);
});
it('should inject a valid config.json file', async () => {
after(async () => {
await fs.unlink(tmpDummyPath);
await fs.unlink(tmpMatchingDtJsonPartitionPath);
await fs.unlink(tmpNonMatchingDtJsonPartitionPath);
});
it('should detect the OS version and inject a valid config.json file to a 6.0.13 image with partition 12 as boot & matching device-type.json', async () => {
api.expectGetApplication();
api.expectGetConfigDeviceTypes();
api.expectGetDeviceTypes();
// It should not reach to /config or /device-types/v1 but instead find
// everything required from the device-type.json in the image.
// api.expectGetConfigDeviceTypes();
api.expectDownloadConfig();
const command: string[] = [
`os configure ${tmpPath}`,
'--device-type raspberrypi3',
'--version 2.47.0+rev1',
`os configure ${tmpMatchingDtJsonPartitionPath}`,
'--device-type jetson-nano',
'--fleet testApp',
'--config-app-update-poll-interval 10',
'--config-network ethernet',
@ -65,8 +129,117 @@ if (process.platform !== 'win32') {
expect(err.join('')).to.equal('');
// confirm the image contains a config.json...
const imagefs = await import('balena-image-fs');
const config = await imagefs.interact(tmpPath, 1, async (_fs) => {
const config = await imagefs.interact(
tmpMatchingDtJsonPartitionPath,
12,
async (_fs) => {
const readFileAsync = promisify(_fs.readFile);
const dtJson = JSON.parse(
await readFileAsync('/device-type.json', { encoding: 'utf8' }),
);
// confirm that the device-type.json mentions the expected partition
expect(dtJson).to.have.nested.property(
'configuration.config.partition',
12,
);
return await readFileAsync('/config.json');
},
);
expect(config).to.not.be.empty;
// confirm the image has the correct config.json values...
const configObj = JSON.parse(config.toString('utf8'));
expect(configObj).to.have.property('deviceType', 'jetson-nano');
expect(configObj).to.have.property('initialDeviceName', 'testDeviceName');
});
it('should detect the OS version and inject a valid config.json file to a 6.1.25 image with partition 12 as boot & a non-matching device-type.json', async () => {
api.expectGetApplication();
api.expectGetDeviceTypes();
// It should not reach to /config or /device-types/v1 but instead find
// everything required from the device-type.json in the image.
// api.expectGetConfigDeviceTypes();
api.expectDownloadConfig();
const command: string[] = [
`os configure ${tmpNonMatchingDtJsonPartitionPath}`,
'--device-type jetson-nano',
'--fleet testApp',
'--config-app-update-poll-interval 10',
'--config-network ethernet',
'--initial-device-name testDeviceName',
'--provisioning-key-name testKey',
'--provisioning-key-expiry-date 2050-12-12',
];
const { err } = await runCommand(command.join(' '));
expect(err.join('')).to.equal('');
// confirm the image contains a config.json...
const config = await imagefs.interact(
tmpNonMatchingDtJsonPartitionPath,
12,
async (_fs) => {
const readFileAsync = promisify(_fs.readFile);
const dtJson = JSON.parse(
await readFileAsync('/device-type.json', { encoding: 'utf8' }),
);
// confirm that the device-type.json mentions the expected partition
expect(dtJson).to.have.nested.property(
'configuration.config.partition',
999,
);
return await readFileAsync('/config.json');
},
);
expect(config).to.not.be.empty;
// confirm the image has the correct config.json values...
const configObj = JSON.parse(config.toString('utf8'));
expect(configObj).to.have.property('deviceType', 'jetson-nano');
expect(configObj).to.have.property('initialDeviceName', 'testDeviceName');
});
// TODO: In the next major consider just failing when we can't find a device-types.json in the image.
it('should inject a valid config.json file to a dummy image', async () => {
api.expectGetApplication();
// Since the dummy image doesn't include a device-type.json
// we have to reach to the API to fetch the manifest of the device type.
api.expectGetConfigDeviceTypes();
api.expectDownloadConfig();
const command: string[] = [
`os configure ${tmpDummyPath}`,
'--device-type raspberrypi3',
'--version 2.47.0+rev1',
'--fleet testApp',
'--config-app-update-poll-interval 10',
'--config-network ethernet',
'--initial-device-name testDeviceName',
'--provisioning-key-name testKey',
'--provisioning-key-expiry-date 2050-12-12',
];
const { err } = await runCommand(command.join(' '));
// Once we replace the dummy.img with one that includes a os-release & device-type.json
// then we should be able to change this to expect no errors.
expect(
err.flatMap((line) => line.split('\n')).filter((line) => line !== ''),
).to.deep.equal(
stripIndent`
[warn] "${tmpDummyPath}":
[warn] 1 partition(s) found, but none containing file "/device-type.json".
[warn] Assuming default boot partition number '1'.
[warn] "${tmpDummyPath}":
[warn] Could not find a previous "/config.json" file in partition '1'.
[warn] Proceeding anyway, but this is unexpected.
[warn] Error while finding a device-type.json on the provided image path. Attempting to fetch from the API.`.split(
'\n',
),
);
// confirm the image contains a config.json...
const config = await imagefs.interact(tmpDummyPath, 1, async (_fs) => {
return await promisify(_fs.readFile)('/config.json');
});
expect(config).to.not.be.empty;

View File

@ -61,22 +61,25 @@ export class BalenaAPIMock extends NockMock {
}
public expectDownloadConfig(opts: ScopeOpts = {}) {
this.optPost('/download-config', opts).reply(
200,
JSON.parse(`{
"applicationId":1301645,
"deviceType":"raspberrypi3",
"userId":43699,
"appUpdatePollInterval":600000,
"listenPort":48484,
"vpnPort":443,
"apiEndpoint":"https://api.balena-cloud.com",
"vpnEndpoint":"vpn.balena-cloud.com",
"registryEndpoint":"registry2.balena-cloud.com",
"deltaEndpoint":"https://delta.balena-cloud.com",
"apiKey":"nothingtoseehere"
}`),
);
this.optPost('/download-config', opts).reply(200, (_uri, body) => {
let deviceType = 'raspberrypi3';
if (typeof body === 'object' && 'deviceType' in body) {
deviceType = body.deviceType;
}
return JSON.parse(`{
"applicationId":1301645,
"deviceType":"${deviceType}",
"userId":43699,
"appUpdatePollInterval":600000,
"listenPort":48484,
"vpnPort":443,
"apiEndpoint":"https://api.balena-cloud.com",
"vpnEndpoint":"vpn.balena-cloud.com",
"registryEndpoint":"registry2.balena-cloud.com",
"deltaEndpoint":"https://delta.balena-cloud.com",
"apiKey":"nothingtoseehere"
}`);
});
}
public expectApplicationProvisioning(opts: ScopeOpts = {}) {

View File

@ -1,105 +0,0 @@
/**
* @license
* Copyright 2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare module 'balena-device-init' {
import type { DeviceTypeJson } from 'balena-sdk';
interface OperationState {
operation:
| CopyOperation
| ReplaceOperation
| RunScriptOperation
| BurnOperation;
percentage: number;
}
interface Operation {
command: string;
}
interface CopyOperation extends Operation {
command: 'copy';
from: { path: string };
to: { path: string };
}
interface ReplaceOperation extends Operation {
command: 'replace';
copy: string;
replace: string;
file: {
path: string;
};
}
interface RunScriptOperation extends Operation {
command: 'run-script';
script: string;
arguments?: string[];
}
interface BurnOperation extends Operation {
command: 'burn';
image?: string;
}
interface BurnProgress {
type: 'write' | 'check';
percentage: number;
transferred: number;
length: number;
remaining: number;
eta: number;
runtime: number;
delta: number;
speed: number;
}
interface InitializeEmitter {
on(event: 'stdout' | 'stderr', callback: (msg: string) => void): void;
on(event: 'state', callback: (state: OperationState) => void): void;
on(event: 'burn', callback: (state: BurnProgress) => void): void;
on(event: 'end', callback: () => void): void;
on(event: 'error', callback: (error: Error) => void): void;
}
// As of writing this, these are Bluebird promises, but we are typing then
// as normal Promises so that we do not rely on Bluebird specific methods,
// so that the CLI will not require any change once the package drops Bluebird.
export function configure(
image: string,
manifest: DeviceTypeJson.DeviceType,
config: object,
options?: object,
): Promise<InitializeEmitter>;
export function initialize(
image: string,
manifest: DeviceTypeJson.DeviceType,
config: object,
): Promise<InitializeEmitter>;
export function getImageOsVersion(
image: string,
manifest: DeviceTypeJson.DeviceType,
): Promise<string | null>;
export function getImageManifest(
image: string,
): Promise<DeviceTypeJson.DeviceType | null>;
}