-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #122 from dappnode/v0.1.15
v0.1.15 Former-commit-id: 2cf0b9a
- Loading branch information
Showing
7 changed files
with
96 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,12 @@ const parse = require('utils/parse'); | |
const {download, run} = require('modules/packages'); | ||
const dappGet = require('modules/dappGet'); | ||
const logUI = require('utils/logUI'); | ||
const isIpfsRequest = require('utils/isIpfsRequest'); | ||
const getManifest = require('modules/getManifest'); | ||
const dockerList = require('modules/dockerList'); | ||
const {eventBus, eventBusTag} = require('eventBus'); | ||
const isSyncing = require('utils/isSyncing'); | ||
const logs = require('logs.js')(module); | ||
|
||
|
||
/** | ||
|
@@ -33,35 +36,75 @@ const installPackage = async ({ | |
logId, | ||
options = {}, | ||
}) => { | ||
if (await isSyncing()) { | ||
throw Error('Mainnet is syncing'); | ||
} | ||
|
||
// 1. Parse the id into a request | ||
// id = '[email protected]' | ||
// req = { name: 'otpweb.dnp.dappnode.eth', ver: '0.1.4' } | ||
const req = parse.packageReq(id); | ||
|
||
// 2. Resolve the request | ||
try { | ||
await dappGet.update(req); | ||
} catch (e) { | ||
throw Error(`Error updating DNP repo: ${e.stack || e.message}`); | ||
// If the request is not from IPFS, check if the chain is syncing | ||
if (!isIpfsRequest(req) && await isSyncing()) { | ||
throw Error('Mainnet is syncing'); | ||
} | ||
|
||
// 2. Resolve the request | ||
let result; | ||
// res = { | ||
// success: {'bind.dnp.dappnode.eth': '0.1.4'} | ||
// state: {'bind.dnp.dappnode.eth': '0.1.2'} | ||
// } | ||
try { | ||
result = await dappGet.resolve(req); | ||
} catch (e) { | ||
throw Error(`Error resolving dependencies: ${e.stack || e.message}`); | ||
} | ||
// Return error if the req couldn't be resolved | ||
if (!result.success) { | ||
throw Error('Request could not be resolved: '+req.name+'@'+req.ver); | ||
if (options.BYPASS_RESOLVER) { | ||
/** | ||
* The dappGet resolver may cause errors. | ||
* Updating the core will never require dependency resolution, | ||
* therefore for a system update the dappGet resolver will be emitted | ||
* | ||
* If BYPASS_RESOLVER == true, just fetch the first level dependencies of the request | ||
*/ | ||
const reqManifest = await getManifest(req); | ||
// reqManifest.dependencies = { | ||
// 'bind.dnp.dappnode.eth': '0.1.4', | ||
// 'admin.dnp.dappnode.eth': '/ipfs/Qm...', | ||
// } | ||
|
||
// Append dependencies in the list of packages to install | ||
result = { | ||
success: (reqManifest || {}).dependencies || {}, | ||
state: {}, | ||
}; | ||
// Add current request to pacakages to install | ||
result.success[req.name] = req.ver; | ||
|
||
// The function below does not directly affect funcionality. | ||
// However it would prevent already installed packages from installing | ||
try { | ||
(await dockerList.listContainers()).forEach((pkg) => { | ||
if (pkg.name && pkg.version | ||
&& result.success && result.success[pkg.name] | ||
&& result.success[pkg.name] === pkg.version) { | ||
delete result.success[pkg.name]; | ||
} | ||
}); | ||
} catch (e) { | ||
logs.error('Error listing current containers: '+e); | ||
} | ||
} else { | ||
/** | ||
* If BYPASS_RESOLVER == false, use the resolver | ||
*/ | ||
try { | ||
await dappGet.update(req); | ||
} catch (e) { | ||
throw Error(`Error updating DNP repo: ${e.stack || e.message}`); | ||
} | ||
// res = { | ||
// success: {'bind.dnp.dappnode.eth': '0.1.4'} | ||
// state: {'bind.dnp.dappnode.eth': '0.1.2'} | ||
// } | ||
try { | ||
result = await dappGet.resolve(req); | ||
} catch (e) { | ||
throw Error(`Error resolving dependencies: ${e.stack || e.message}`); | ||
} | ||
// Return error if the req couldn't be resolved | ||
if (!result.success) { | ||
throw Error('Request could not be resolved: '+req.name+'@'+req.ver); | ||
} | ||
} | ||
|
||
const {success: newState, state} = result; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,8 @@ | ||
const parse = require('utils/parse'); | ||
const {download, run} = require('modules/packages'); | ||
const {eventBus, eventBusTag} = require('eventBus'); | ||
const getManifest = require('modules/getManifest'); | ||
const dockerList = require('modules/dockerList'); | ||
const logs = require('logs.js')(module); | ||
const installPackage = require('./installPackage'); | ||
|
||
|
||
/** | ||
* Installs a package. It resolves dependencies, downloads | ||
* manifests and images, loads the images to docker, and calls | ||
* docker up on each package. | ||
* It has extra functionality for special cases | ||
* - allowCore: If a manifest requests a package to be core | ||
* it will only be granted if | ||
* 1. Its manifest comes from APM and .dnp.dappnode.eth | ||
* 2. It comes from IPFS and the BYPASS_CORE_RESTRICTION env is true | ||
* - Special versions: It needs to deal with two cases | ||
* 1. ver = 'latest' | ||
* 2. ver = '/ipfs/QmZ87fb2...' | ||
* Installs a package in safe mode, by setting options.BYPASS_RESOLVER = true | ||
* | ||
* @param {Object} kwargs: { | ||
* id: package .eth name (string) | ||
|
@@ -28,85 +13,12 @@ const logs = require('logs.js')(module); | |
*/ | ||
const installPackageSafe = async ({ | ||
id, | ||
vols = {}, | ||
logId, | ||
options = {}, | ||
}) => { | ||
// 1. Parse the id into a request | ||
// id = '[email protected]' | ||
// req = { name: 'otpweb.dnp.dappnode.eth', ver: '0.1.4' } | ||
const req = parse.packageReq(id); | ||
|
||
// 2. Only get first order dependencies | ||
const manifest = await getManifest(req); | ||
if (!manifest) { | ||
throw Error('Manifest could not be found for: '+req.name+'@'+req.ver); | ||
} | ||
let pkgs = [ | ||
{ | ||
name: req.name, | ||
ver: req.ver, | ||
manifest, | ||
}, | ||
]; | ||
const dependencies = manifest.dependencies || {}; | ||
await Promise.all(Object.keys(dependencies).map(async (dep) => { | ||
const depManifest = await getManifest(parse.packageReq(dep)); | ||
if (!depManifest) { | ||
throw Error('Manifest could not be found for: '+dep); | ||
} | ||
pkgs.push({ | ||
name: dep, | ||
ver: depManifest.version, | ||
manifest: depManifest, | ||
}); | ||
})); | ||
|
||
// 3. Only install packages that have to be updated | ||
let dnpList = []; | ||
try { | ||
dnpList = await dockerList.listContainers(); | ||
} catch (e) { | ||
logs.error('Error listing current containers: '+e); | ||
} | ||
|
||
pkgs = pkgs.filter((pkg) => { | ||
const currentPkg = dnpList.find((_pkg) => _pkg.name === pkg.name); | ||
if (currentPkg && currentPkg.version && pkg.ver) { | ||
return currentPkg.version !== pkg.ver; | ||
} else { | ||
return true; | ||
} | ||
}); | ||
|
||
|
||
// 4. Download requested packages | ||
await Promise.all(pkgs.map((pkg) => download({pkg, logId}))); | ||
|
||
// 5. Run requested packages | ||
// Patch, install the dappmanager the last always | ||
let dappmanagerPkg; | ||
await Promise.all(pkgs | ||
.filter((pkg) => { | ||
if (pkg.manifest.name.includes('dappmanager.dnp.dappnode.eth')) { | ||
dappmanagerPkg = pkg; | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
}).map((pkg) => run({pkg, logId}))); | ||
|
||
if (dappmanagerPkg) await run({pkg: dappmanagerPkg, logId}); | ||
|
||
// 6. Clean install files | ||
|
||
// Emit packages update | ||
eventBus.emit(eventBusTag.emitPackages); | ||
|
||
return { | ||
message: 'Installed ' + req.req, | ||
logMessage: true, | ||
userAction: true, | ||
}; | ||
options.BYPASS_RESOLVER = true; | ||
return await installPackage({id, vols, logId, options}); | ||
}; | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const isIpfsHash = require('./isIpfsHash'); | ||
|
||
const isIpfsRequest = (req) => { | ||
if (req && typeof req === 'object') { | ||
return req.name && isIpfsHash(req.name) | ||
|| req.ver && isIpfsHash(req.ver); | ||
} else if (req && typeof req === 'string') { | ||
return isIpfsHash(req); | ||
} else { | ||
return false; | ||
} | ||
}; | ||
|
||
module.exports = isIpfsRequest; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters