Support the new OS with resin-sample.ignore connection file

This commit is contained in:
Eugene Mirotin 2017-07-26 22:48:27 +03:00
parent 759baf3eda
commit 22e0b4b9dc
6 changed files with 296 additions and 4105 deletions

View File

@ -2,3 +2,4 @@ tests
doc
lib
extras
tmp

View File

@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
### Changed
- Support the new resinOS versions where the sample connection file is called `resin-sample.ignore`
## [6.1.1] - 2017-07-18
### Changed

View File

@ -15,49 +15,143 @@ 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.
*/
var CONFIGURATION_SCHEMA;
var BOOT_PARTITION, CONNECTIONS_FOLDER, CONNECTION_FILE, getConfiguration, getConfigurationSchema, inquirerOptions, prepareConnectionFile;
CONFIGURATION_SCHEMA = {
mapper: [
{
template: {
hostname: '{{hostname}}',
persistentLogging: '{{persistentLogging}}'
},
domain: [['config_json', 'hostname'], ['config_json', 'persistentLogging']]
}, {
template: {
wifi: {
ssid: '{{networkSsid}}'
},
'wifi-security': {
psk: '{{networkKey}}'
}
},
domain: [['system_connections', 'resin-sample', 'wifi'], ['system_connections', 'resin-sample', 'wifi-security']]
}
],
files: {
system_connections: {
fileset: true,
type: 'ini',
location: {
path: 'system-connections',
partition: {
primary: 1
}
}
},
config_json: {
type: 'json',
location: {
path: 'config.json',
partition: {
primary: 1
}
}
}
BOOT_PARTITION = {
primary: 1
};
CONNECTIONS_FOLDER = '/system-connections';
getConfigurationSchema = function(connnectionFileName) {
if (connnectionFileName == null) {
connnectionFileName = 'resin-wifi';
}
return {
mapper: [
{
template: {
hostname: '{{hostname}}',
persistentLogging: '{{persistentLogging}}'
},
domain: [['config_json', 'hostname'], ['config_json', 'persistentLogging']]
}, {
template: {
wifi: {
ssid: '{{networkSsid}}'
},
'wifi-security': {
psk: '{{networkKey}}'
}
},
domain: [['system_connections', connnectionFileName, 'wifi'], ['system_connections', connnectionFileName, 'wifi-security']]
}
],
files: {
system_connections: {
fileset: true,
type: 'ini',
location: {
path: CONNECTIONS_FOLDER.slice(1),
partition: BOOT_PARTITION
}
},
config_json: {
type: 'json',
location: {
path: 'config.json',
partition: BOOT_PARTITION
}
}
}
};
};
inquirerOptions = function(data) {
return [
{
message: 'Network SSID',
type: 'input',
name: 'networkSsid',
"default": data.networkSsid
}, {
message: 'Network Key',
type: 'input',
name: 'networkKey',
"default": data.networkKey
}, {
message: 'Do you want to set advanced settings?',
type: 'confirm',
name: 'advancedSettings',
"default": false
}, {
message: 'Device Hostname',
type: 'input',
name: 'hostname',
"default": data.hostname,
when: function(answers) {
return answers.advancedSettings;
}
}, {
message: 'Do you want to enable persistent logging?',
type: 'confirm',
name: 'persistentLogging',
"default": data.persistentLogging,
when: function(answers) {
return answers.advancedSettings;
}
}
];
};
getConfiguration = function(data) {
var _, inquirer;
_ = require('lodash');
inquirer = require('inquirer');
data = _.assign(data, {
persistentLogging: data.persistentLogging || false
});
return inquirer.prompt(inquirerOptions(data)).then(function(answers) {
return _.merge(data, answers);
});
};
CONNECTION_FILE = '[connection]\nid=resin-wifi\ntype=wifi\n\n[wifi]\nhidden=true\nmode=infrastructure\nssid=My_Wifi_Ssid\n\n[wifi-security]\nauth-alg=open\nkey-mgmt=wpa-psk\npsk=super_secret_wifi_password\n\n[ipv4]\nmethod=auto\n\n[ipv6]\naddr-gen-mode=stable-privacy\nmethod=auto';
prepareConnectionFile = function(target) {
var _, imagefs;
_ = require('lodash');
imagefs = require('resin-image-fs');
return imagefs.listDirectory({
image: target,
partition: BOOT_PARTITION,
path: CONNECTIONS_FOLDER
}).then(function(files) {
if (_.includes(files, 'resin-wifi')) {
return null;
}
if (_.includes(files, 'resin-sample.ignore')) {
return imagefs.copy({
image: target,
partition: BOOT_PARTITION,
path: CONNECTIONS_FOLDER + "/resin-sample.ignore"
}, {
image: target,
partition: BOOT_PARTITION,
path: CONNECTIONS_FOLDER + "/resin-wifi"
}).thenReturn(null);
}
if (_.includes(files, 'resin-sample')) {
return 'resin-sample';
}
return imagefs.writeFile({
image: target,
partition: BOOT_PARTITION,
path: CONNECTIONS_FOLDER + "/resin-wifi"
}, CONNECTION_FILE).thenReturn(null);
}).then(function(connnectionFileName) {
return getConfigurationSchema(connnectionFileName);
});
};
module.exports = {
@ -66,62 +160,24 @@ module.exports = {
help: 'Use this command to configure or reconfigure a resinOS drive or image.\n\nExamples:\n\n $ resin local configure /dev/sdc\n $ resin local configure path/to/image.img',
root: true,
action: function(params, options, done) {
var Promise, _, denymount, inquirer, isMountedAsync, reconfix, umount, umountAsync;
_ = require('lodash');
var Promise, denymount, isMountedAsync, reconfix, umount, umountAsync;
Promise = require('bluebird');
umount = require('umount');
umountAsync = Promise.promisify(umount.umount);
isMountedAsync = Promise.promisify(umount.isMounted);
inquirer = require('inquirer');
reconfix = require('reconfix');
denymount = Promise.promisify(require('denymount'));
return isMountedAsync(params.target).then(function(isMounted) {
if (!isMounted) {
return;
}
return umountAsync(params.target);
}).then(function() {
return prepareConnectionFile(params.target).tap(function() {
return isMountedAsync(params.target).then(function(isMounted) {
if (!isMounted) {
return;
}
return umountAsync(params.target);
});
}).then(function(configurationSchema) {
return denymount(params.target, function(cb) {
return reconfix.readConfiguration(CONFIGURATION_SCHEMA, params.target).then(function(data) {
data.persistentLogging = data.persistentLogging || false;
return inquirer.prompt([
{
message: 'Network SSID',
type: 'input',
name: 'networkSsid',
"default": data.networkSsid
}, {
message: 'Network Key',
type: 'input',
name: 'networkKey',
"default": data.networkKey
}, {
message: 'Do you want to set advanced settings?',
type: 'confirm',
name: 'advancedSettings',
"default": false
}, {
message: 'Device Hostname',
type: 'input',
name: 'hostname',
"default": data.hostname,
when: function(answers) {
return answers.advancedSettings;
}
}, {
message: 'Do you want to enable persistent logging?',
type: 'confirm',
name: 'persistentLogging',
"default": data.persistentLogging,
when: function(answers) {
return answers.advancedSettings;
}
}
]).then(function(answers) {
return _.merge(data, answers);
});
}).then(function(answers) {
return reconfix.writeConfiguration(CONFIGURATION_SCHEMA, answers, params.target);
return reconfix.readConfiguration(configurationSchema, params.target).then(getConfiguration).then(function(answers) {
return reconfix.writeConfiguration(configurationSchema, answers, params.target);
}).asCallback(cb);
});
}).then(function() {

View File

@ -14,7 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
###
CONFIGURATION_SCHEMA =
BOOT_PARTITION = { primary: 1 }
CONNECTIONS_FOLDER = '/system-connections'
getConfigurationSchema = (connnectionFileName = 'resin-wifi') ->
mapper: [
{
template:
@ -32,8 +35,8 @@ CONFIGURATION_SCHEMA =
'wifi-security':
psk: '{{networkKey}}'
domain: [
[ 'system_connections', 'resin-sample', 'wifi' ]
[ 'system_connections', 'resin-sample', 'wifi-security' ]
[ 'system_connections', connnectionFileName, 'wifi' ]
[ 'system_connections', connnectionFileName, 'wifi-security' ]
]
}
]
@ -42,15 +45,139 @@ CONFIGURATION_SCHEMA =
fileset: true
type: 'ini'
location:
path: 'system-connections'
partition:
primary: 1
path: CONNECTIONS_FOLDER.slice(1)
partition: BOOT_PARTITION
config_json:
type: 'json'
location:
path: 'config.json'
partition:
primary: 1
partition: BOOT_PARTITION
inquirerOptions = (data) -> [
{
message: 'Network SSID'
type: 'input'
name: 'networkSsid'
default: data.networkSsid
}
{
message: 'Network Key'
type: 'input'
name: 'networkKey'
default: data.networkKey
}
{
message: 'Do you want to set advanced settings?'
type: 'confirm'
name: 'advancedSettings'
default: false
}
{
message: 'Device Hostname'
type: 'input'
name: 'hostname'
default: data.hostname,
when: (answers) ->
answers.advancedSettings
}
{
message: 'Do you want to enable persistent logging?'
type: 'confirm'
name: 'persistentLogging'
default: data.persistentLogging
when: (answers) ->
answers.advancedSettings
}
]
getConfiguration = (data) ->
_ = require('lodash')
inquirer = require('inquirer')
# `persistentLogging` can be `undefined`, so we want
# to make sure that case defaults to `false`
data = _.assign data,
persistentLogging: data.persistentLogging or false
inquirer.prompt(inquirerOptions(data))
.then (answers) ->
return _.merge(data, answers)
# Taken from https://goo.gl/kr1kCt
CONNECTION_FILE = '''
[connection]
id=resin-wifi
type=wifi
[wifi]
hidden=true
mode=infrastructure
ssid=My_Wifi_Ssid
[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=super_secret_wifi_password
[ipv4]
method=auto
[ipv6]
addr-gen-mode=stable-privacy
method=auto
'''
###
* if the `resin-wifi` file exists (previously configured image or downloaded from the UI) it's used and reconfigured
* if the `resin-sample.ignore` exists it's copied to `resin-wifi`
* if the `resin-sample` exists it's reconfigured (legacy mode, will be removed eventually)
* otherwise, the new file is created
###
prepareConnectionFile = (target) ->
_ = require('lodash')
imagefs = require('resin-image-fs')
imagefs.listDirectory
image: target
partition: BOOT_PARTITION
path: CONNECTIONS_FOLDER
.then (files) ->
# The required file already exists
if _.includes(files, 'resin-wifi')
return null
# Fresh image, new mode, accoding to https://github.com/resin-os/meta-resin/pull/770/files
if _.includes(files, 'resin-sample.ignore')
return imagefs.copy
image: target
partition: BOOT_PARTITION
path: "#{CONNECTIONS_FOLDER}/resin-sample.ignore"
,
image: target
partition: BOOT_PARTITION
path: "#{CONNECTIONS_FOLDER}/resin-wifi"
.thenReturn(null)
# Legacy mode, to be removed later
# We return the file name override from this branch
# When it is removed the following cleanup should be done:
# * delete all the null returns from this method
# * turn `getConfigurationSchema` back into the constant, with the connection filename always being `resin-wifi`
# * drop the final `then` from this method
# * adapt the code in the main listener to not receive the config from this method, and use that constant instead
if _.includes(files, 'resin-sample')
return 'resin-sample'
# In case there's no file at all (shouldn't happen normally, but the file might have been removed)
return imagefs.writeFile
image: target
partition: BOOT_PARTITION
path: "#{CONNECTIONS_FOLDER}/resin-wifi"
, CONNECTION_FILE
.thenReturn(null)
.then (connnectionFileName) ->
return getConfigurationSchema(connnectionFileName)
module.exports =
signature: 'local configure <target>'
@ -65,65 +192,24 @@ module.exports =
'''
root: true
action: (params, options, done) ->
_ = require('lodash')
Promise = require('bluebird')
umount = require('umount')
umountAsync = Promise.promisify(umount.umount)
isMountedAsync = Promise.promisify(umount.isMounted)
inquirer = require('inquirer')
reconfix = require('reconfix')
denymount = Promise.promisify(require('denymount'))
isMountedAsync(params.target).then (isMounted) ->
return if not isMounted
umountAsync(params.target)
.then ->
prepareConnectionFile(params.target)
.tap ->
isMountedAsync(params.target).then (isMounted) ->
return if not isMounted
umountAsync(params.target)
.then (configurationSchema) ->
denymount params.target, (cb) ->
reconfix.readConfiguration(CONFIGURATION_SCHEMA, params.target).then (data) ->
# `persistentLogging` can be `undefined`, so we want
# to make sure that case defaults to `false`
data.persistentLogging = data.persistentLogging or false
inquirer.prompt([
{
message: 'Network SSID'
type: 'input'
name: 'networkSsid'
default: data.networkSsid
}
{
message: 'Network Key'
type: 'input'
name: 'networkKey'
default: data.networkKey
}
{
message: 'Do you want to set advanced settings?'
type: 'confirm'
name: 'advancedSettings'
default: false
}
{
message: 'Device Hostname'
type: 'input'
name: 'hostname'
default: data.hostname,
when: (answers) ->
answers.advancedSettings
}
{
message: 'Do you want to enable persistent logging?'
type: 'confirm'
name: 'persistentLogging'
default: data.persistentLogging
when: (answers) ->
answers.advancedSettings
}
]).then (answers) ->
return _.merge(data, answers)
reconfix.readConfiguration(configurationSchema, params.target)
.then(getConfiguration)
.then (answers) ->
reconfix.writeConfiguration(CONFIGURATION_SCHEMA, answers, params.target)
reconfix.writeConfiguration(configurationSchema, answers, params.target)
.asCallback(cb)
.then ->
console.log('Done!')

3956
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -80,7 +80,7 @@
"resin-device-init": "^2.2.1",
"resin-docker-build": "^0.4.0",
"resin-doodles": "0.0.1",
"resin-image-fs": "^2.1.2",
"resin-image-fs": "^2.3.0",
"resin-image-manager": "^4.1.1",
"resin-sdk-preconfigured": "^6.4.1",
"resin-settings-client": "^3.6.1",