From 5826a885421d6fb2ede1e03f2e90d67ac4fac3bb Mon Sep 17 00:00:00 2001 From: pshenmic Date: Wed, 31 Jan 2024 02:03:05 +0400 Subject: [PATCH 1/3] feat(dashmate): try-catch in updateNodeFactory --- .../dashmate/src/update/updateNodeFactory.js | 22 ++++++++-- .../test/unit/commands/update.spec.js | 40 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/packages/dashmate/src/update/updateNodeFactory.js b/packages/dashmate/src/update/updateNodeFactory.js index 79996a2511d..5046c6a0041 100644 --- a/packages/dashmate/src/update/updateNodeFactory.js +++ b/packages/dashmate/src/update/updateNodeFactory.js @@ -19,10 +19,17 @@ export default function updateNodeFactory(getServiceList, docker) { return Promise.all( lodash.uniqBy(services, 'image') - .map(async ({ name, image, title }) => new Promise((resolve, reject) => { + .map(async ({ name, image, title }) => new Promise((resolve) => { docker.pull(image, (err, stream) => { if (err) { - reject(err); + if (process.env.DEBUG) { + // eslint-disable-next-line no-console + console.error(`Failed to update ${name} service, image ${image}, error: ${err}`); + } + + resolve({ + name, title, image, updated: false, + }); } else { let updated = null; @@ -41,7 +48,16 @@ export default function updateNodeFactory(getServiceList, docker) { updated = true; } }); - stream.on('error', reject); + stream.on('error', () => { + if (process.env.DEBUG) { + // eslint-disable-next-line no-console + console.error(`Failed to update ${name} service, image ${image}, error: ${err}`); + } + + resolve({ + name, title, image, updated: false, + }); + }); stream.on('end', () => resolve({ name, title, image, updated, })); diff --git a/packages/dashmate/test/unit/commands/update.spec.js b/packages/dashmate/test/unit/commands/update.spec.js index ecf95ad7a39..12536a22930 100644 --- a/packages/dashmate/test/unit/commands/update.spec.js +++ b/packages/dashmate/test/unit/commands/update.spec.js @@ -42,4 +42,44 @@ describe('Update command', () => { expect(mockGetServicesList).to.have.been.calledOnceWithExactly(config); expect(mockDocker.pull).to.have.been.calledOnceWith(mockServicesList[0].image); }); + + it('should update other services if one of them fails', async function it() { + const command = new UpdateCommand(); + mockDockerResponse = { status: 'Status: Image is up to date for' }; + mockServicesList = [{ name: 'fake', image: 'fake', title: 'FAKE' }, + { name: 'fake_docker_pull_error', image: 'fake_err_image', title: 'FAKE_ERROR' }]; + + // test docker.pull returns error + mockDocker = { + pull: this.sinon.stub() + .callsFake((image, cb) => (image === mockServicesList[1].image ? cb(new Error(), null) + : cb(false, mockDockerStream))), + }; + + let updateNode = updateNodeFactory(mockGetServicesList, mockDocker); + + await command.runWithDependencies({}, { format: 'json' }, mockDocker, config, updateNode); + + expect(mockGetServicesList).to.have.been.calledOnceWithExactly(config); + expect(mockDocker.pull.firstCall.firstArg).to.equal(mockServicesList[0].image); + expect(mockDocker.pull.secondCall.firstArg).to.equal(mockServicesList[1].image); + + // test docker.pull stream returns error + mockDocker = { pull: this.sinon.stub().callsFake((image, cb) => cb(false, mockDockerStream)) }; + mockDockerStream = { + on: this.sinon.stub().callsFake((channel, cb) => (channel === 'error' ? cb(new Error()) : null)), + }; + + // reset + mockGetServicesList = this.sinon.stub().callsFake(() => mockServicesList); + mockDocker = { pull: this.sinon.stub().callsFake((image, cb) => cb(false, mockDockerStream)) }; + + updateNode = updateNodeFactory(mockGetServicesList, mockDocker); + + await command.runWithDependencies({}, { format: 'json' }, mockDocker, config, updateNode); + + expect(mockGetServicesList).to.have.been.calledOnceWithExactly(config); + expect(mockDocker.pull.firstCall.firstArg).to.equal(mockServicesList[0].image); + expect(mockDocker.pull.secondCall.firstArg).to.equal(mockServicesList[1].image); + }); }); From d153165f33c7f0193c6bf898fd45bdc3ade1ebd6 Mon Sep 17 00:00:00 2001 From: pshenmic Date: Thu, 14 Mar 2024 15:08:19 +0300 Subject: [PATCH 2/3] feat(dashmate): add error status to dashmate update --- packages/dashmate/src/commands/update.js | 8 +++++++- packages/dashmate/src/update/updateNodeFactory.js | 8 ++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/dashmate/src/commands/update.js b/packages/dashmate/src/commands/update.js index 8ba5b774d25..dce6b2c6790 100644 --- a/packages/dashmate/src/commands/update.js +++ b/packages/dashmate/src/commands/update.js @@ -35,6 +35,12 @@ export default class UpdateCommand extends ConfigBaseCommand { ) { const updateInfo = await updateNode(config); + const colors = { + updated: chalk.yellow, + 'up to date': chalk.green, + error: chalk.red, + }; + // Draw table or show json printArrayOfObjects(updateInfo .reduce( @@ -43,7 +49,7 @@ export default class UpdateCommand extends ConfigBaseCommand { }) => ([ ...acc, format === OUTPUT_FORMATS.PLAIN - ? { Service: title, Image: image, Updated: updated ? chalk.yellow('updated') : chalk.green('up to date') } + ? { Service: title, Image: image, Updated: colors[updated](updated) } : { name, title, updated, image, }, diff --git a/packages/dashmate/src/update/updateNodeFactory.js b/packages/dashmate/src/update/updateNodeFactory.js index 5046c6a0041..b4e6260d795 100644 --- a/packages/dashmate/src/update/updateNodeFactory.js +++ b/packages/dashmate/src/update/updateNodeFactory.js @@ -28,7 +28,7 @@ export default function updateNodeFactory(getServiceList, docker) { } resolve({ - name, title, image, updated: false, + name, title, image, updated: 'error', }); } else { let updated = null; @@ -43,9 +43,9 @@ export default function updateNodeFactory(getServiceList, docker) { .filter((obj) => obj.status.startsWith('Status: ')); if (status?.status.includes('Image is up to date for')) { - updated = false; + updated = 'up to date'; } else if (status?.status.includes('Downloaded newer image for')) { - updated = true; + updated = 'updated'; } }); stream.on('error', () => { @@ -55,7 +55,7 @@ export default function updateNodeFactory(getServiceList, docker) { } resolve({ - name, title, image, updated: false, + name, title, image, updated: 'error', }); }); stream.on('end', () => resolve({ From b70fd6d6d2161ecc446e6cfc1ed32ee1c6daa992 Mon Sep 17 00:00:00 2001 From: pshenmic Date: Sun, 5 May 2024 18:26:42 +0700 Subject: [PATCH 3/3] feat(dashmate): add check for null status --- .../dashmate/src/update/updateNodeFactory.js | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/dashmate/src/update/updateNodeFactory.js b/packages/dashmate/src/update/updateNodeFactory.js index b4e6260d795..9ce4fb126a4 100644 --- a/packages/dashmate/src/update/updateNodeFactory.js +++ b/packages/dashmate/src/update/updateNodeFactory.js @@ -40,12 +40,23 @@ export default function updateNodeFactory(getServiceList, docker) { .trim() .split('\r\n') .map((str) => JSON.parse(str)) - .filter((obj) => obj.status.startsWith('Status: ')); + .filter((obj) => obj?.status?.startsWith('Status: ')); - if (status?.status.includes('Image is up to date for')) { - updated = 'up to date'; - } else if (status?.status.includes('Downloaded newer image for')) { - updated = 'updated'; + if (status) { + if (status.status.includes('Image is up to date for')) { + updated = 'up to date'; + } else if (status.status.includes('Downloaded newer image for')) { + updated = 'updated'; + } + } else { + if (process.env.DEBUG) { + // eslint-disable-next-line no-console + console.error('Failed to read docker json data, status not found'); + } + + resolve({ + name, title, image, updated: 'error', + }); } }); stream.on('error', () => {