Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make .configure() configure network settings for both 1.x & 2.x #25

Merged
merged 16 commits into from
Nov 28, 2017

Conversation

pimterry
Copy link
Contributor

@pimterry pimterry commented Oct 27, 2017

Connects to balena-io/balena-cli#494
Connects to balena-io/balena-cli#537

This PR does a lot of exciting things. Primarily, it ensures that resin-device-init knows how to initialize a device's network, not just its config.json. Lots of the logic to do that comes from the reconfix test framework's schemas, and the existing logic to do this for ResinOS 2.x images in the CLI (which will be removed shortly to start using this instead).

On top of that, this upgrades to resin-image-fs v4 (since that's a prerequisite), adds logic for OS version detection (some context in flowdock) since we need that to decide which type of network config to do, and updates the npm build script to always rebuild the docs, and build before you test, since that's easy to forget otherwise.

Some of this is arguably a little hacky, though I've tried to minimize that. A lot of that is due to limitations and outright bugs in the current reconfix implementation. I'm just working around those for now, since the JS reconfix is deprecated, and we should be replacing those parts with Rust reconfix soon-ish hopefully.

This isn't totally done - I still need to add some proper tests for this, but those are slightly tricky. It'd be useful if you could start on reviewing the implementation logic in the meantime though, and I'll patch some add some more thorough tests for this later too.

@pimterry pimterry requested a review from zvin October 27, 2017 12:27
@pimterry pimterry mentioned this pull request Oct 27, 2017
lib/init.coffee Outdated
if not majorVersion? || majorVersion == 2
network.configureOS2Network(image, manifest, options)
if not majorVersion? || majorVersion == 1
network.configureOS1Network(image, manifest, options)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block (the one that configures network) should use Promise.all or Promise.join to we wait for both operations to complete.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe it should use thens . I don't know if reconfix suppports doing things in parallel.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it'll do undefined things if you try to write changes in parallel. I've made it wait on these synchronously instead.


_ = require('lodash')
path = require('path')
utils = require('./utils')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: can we put local imports after the other ones?

contents.files ?= {}
contents.files['network/network.config'] ?= ''
imagefs.writeFile(configFilePath, JSON.stringify(contents))
.catch fileNotFoundError, ->
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use .catch { code: 'ENOENT' }, -> directly with Bluebird.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this catch is here to catch errors of imagefs.readFile(configFilePath), can we put it right after it (before JSON.parse)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use .catch { code: 'ENOENT' }, -> directly with Bluebird.

Sadly, this is using the promise returned from resin-image-fs, which uses an old version of bluebird that can't do this, and throws https://github.com/petkaantonov/bluebird/wiki/Error:-Catch-filter-must-inherit-from-Error-or-be-a-simple-predicate-function instead.

If this catch is here to catch errors of imagefs.readFile(configFilePath), can we put it right after it (before JSON.parse)?

Done.

.then ->
schema = getOS2WifiConfigurationSchema(manifest, answers)
if manifest.configuration.config.image
image = path.join(image, manifest.configuration.config.image)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must be missing something but how does this work if image is not a folder ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anwswer to myself: that must be for edison images.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. If you try to configure a single image as an edison image you'll get errors complaining that myimage.img/resin-image-edison.hddimg does not exist, but imo that's not an unreasonable error, and it's a pretty rare case (and trying to configure a raspberry pi image to work for an edison is always going to blow up eventually).

###
connectionsFolderDefinition = utils.definitionForImage(target, getConfigPathDefinition(manifest, CONNECTIONS_FOLDER))

imagefs.listDirectory(connectionsFolderDefinition).then (files) ->
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: can we put the .then (files) -> on the next line?

}
{
domain: [
[ 'network_config', 'service_home_ethernet' ],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: no comma needed here.

location:
getConfigPathDefinition(manifest, '/config.json', false)
network_config:
type: 'ini',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: no comma needed here.

network_config:
type: 'ini',
location:
parent: 'config_json',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: no comma needed here.

mapper: [
{
domain: [
[ 'config_json', 'wifiSsid' ],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: no comma needed here.

lib/utils.coffee Outdated
rindle = Promise.promisifyAll(require('rindle'))
path = require('path')
stringToStream = require('string-to-stream')
streamToString = require('stream-to-string')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use streamToString instead of rindle.extractAsync ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I didn't know it existed 😃. Fixed.

@pimterry
Copy link
Contributor Author

Updated to fix all the comments, except a couple I've replied to separately, and I've also added proper tests for network configuration.

The tests are failing on travis because our ext2fs module uses const, and doesn't actually support Node 4. We don't support Node 4 in the CLI either though, so we could just drop those tests drop support completely here too, unless there's some other reason that needs this to work in Node 4? We could probably make ext2fs backward compatible if we need to, but if not it'd be nice to keep it modern.

Meanwhile, the tests are failing on appveyor because ext2fs doesn't build on windows. This is going to be a bigger problem, since it really needs to build reliably on windows with nothing more than windows-build-tools, or none of our windows users are going to successfully install it. Right now, with that package installed, the current error is:

C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.Cpp.Platform.targets(64,5):
error MSB8020: The build tools for v140 (Platform Toolset = 'v140') cannot be found. To
build using the v140 build tools, please install v140 build tools. Alternatively, you may
upgrade to the current Visual Studio tools by selecting the Project menu or right-click
the solution, and then selecting "Upgrade Solution...".
[C:\projects\resin-device-init-xpd6l\node_modules\ext2fs\build\ext2fs.vcxproj]

I'm not immediately sure how to fix that - any ideas? I can dig into it more, but some pointers in the right direction first would be really useful.

@pimterry
Copy link
Contributor Author

Node-ext2fs issues seem to now be resolved. Next issue that's currently breaking the tests is balena-io/reconfix#33: the reconfix JS implementation breaks with directories on windows. Quick fix, hopefully this will start passing once that's sorted & released.

@pimterry pimterry force-pushed the configure-os2-network branch from 914400c to b06c3b3 Compare November 22, 2017 16:22
@pimterry pimterry requested review from abrodersen and zvin November 22, 2017 16:35
@pimterry
Copy link
Contributor Author

It's alive! Seems to all be working happily on Windows now. I think this means this PR is finally all good and ready to go.

@zvin @abrodersen can you review please?

image: image
partition:
primary: 1
partition: 1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work on a jetson-tx2 where boot is the 12th partition.
Shouldn't matter as there is a fallback.

lib/utils.coffee Outdated
exports.getImageOsVersion = (image) ->
Promise.using imagefs.read(
image: image
partition: 2
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work on a jetson where resin-rootA is the 13th partition and uses the new host apps tree.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this doesn't work for quite a few similar cases too, so there's a .catchReturn(null) below, which should work as the fallback. Returning null from here results in us configuring the image as both OS1 and OS2 for any images where we can't get a specific version easily. That's a little messy, but acceptable for now, and shouldn't break anything.

The plan in future is to eventually stop needing to look at the root partition at all this - instead we'll have an os-release file inside the boot partition itself, so we can use the device types to find it as we do with config.json/system-connections/etc. @agherzan is looking at that here: balena-os/meta-balena#906.

Promise.using imagefs.read(
path: '/config.json'
image: path.join(images.edison, 'resin-image-edison.hddimg')
), extract
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract could be replaced with rindle.extractAsync.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, good idea, but I'm going to ignore this for now anyway. I want to do a bunch of improvements to the tests (e.g. #26) anyway, and we use this extract method everywhere, so I'll probably replace it all with rindle as part of that.

Should've done this originally really. It'd be nice to also fix the
underlying streaming bug (which segfaults when trying to stream a
missing file through ext2fs), but this fixes the issue, and we'll want
this change regardless.
@resin-io-modules-versionbot resin-io-modules-versionbot bot merged commit d1858cb into master Nov 28, 2017
@resin-io-modules-versionbot
Copy link
Contributor

VersionBot failed to carry out a status check for the above pull request here: #25. The reason for this is:
Reference already exists
Please carry out relevant changes or alert an appropriate admin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants