Skip to content

Commit 656a046

Browse files
committed
fix: handle imported networks with missing custom images
1 parent 7c34cae commit 656a046

File tree

5 files changed

+61
-35
lines changed

5 files changed

+61
-35
lines changed

src/components/network/NewNetwork.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ const NewNetwork: React.SFC = () => {
8888
<Styled.Divider orientation="left">{l('customLabel')}</Styled.Divider>
8989
<Row>
9090
{customNodes.map(node => (
91-
<Col span={8} key={node.id}>
91+
<Col span={6} key={node.id}>
9292
<Form.Item
9393
name={['customNodes', node.id]}
9494
label={node.name}

src/components/nodeImages/CustomImageModal.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const CustomImageModal: React.FC<Props> = ({ image, onClose }) => {
4949
};
5050

5151
const implGroups: Record<string, NodeImplementation[]> = {
52-
Lightning: ['LND', 'c-lightning'],
52+
Lightning: ['LND', 'c-lightning', 'eclair'],
5353
Bitcoin: ['bitcoind'],
5454
};
5555

src/i18n/locales/en-US.json

+1
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@
355355
"store.models.network.removeCompatErr": "There are no other compatible backends for {{lnName}} to connect to. You must remove the {{lnName}} node first",
356356
"store.models.network.exportTitle": "Export '{{name}}'",
357357
"store.models.network.exportBadStatus": "The network must be stopped to be exported",
358+
"store.models.network.missingImages": "Cannot start the network because it contains custom node images that are not available on this machine",
358359
"utils.network.backendCompatError": "This network does not contain a Bitcoin Core v{{requiredVersion}} (or lower) node which is required for {{implementation}} v{{version}}",
359360
"utils.network.incompatibleImplementation": "Importing networks with {{implementation}} nodes is not supported on {{platform}}",
360361
"utils.network.unknownImplementation": "Cannot import unknown Lightning implementation '{{implementation}}'"

src/store/models/network.spec.ts

+10
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,16 @@ describe('Network model', () => {
618618
});
619619
expect(logMock.info).toBeCalledWith('Failed to connect all LN peers', err);
620620
});
621+
622+
it('should throw an error if a custom node image is missing', async () => {
623+
const { networks } = store.getState().network;
624+
networks[0].nodes.lightning[0].docker.image = 'custom-image:latest';
625+
store.getActions().network.setNetworks(networks);
626+
const { start } = store.getActions().network;
627+
const errMsg =
628+
'Cannot start the network because it contains custom node images that are not available on this machine: custom-image:latest';
629+
await expect(start(firstNetwork().id)).rejects.toThrow(errMsg);
630+
});
621631
});
622632

623633
describe('Stopping', () => {

src/store/models/network.ts

+48-33
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from 'shared/types';
1313
import { CustomImage, Network, StoreInjections } from 'types';
1414
import { initChartFromNetwork } from 'utils/chart';
15-
import { APP_VERSION } from 'utils/constants';
15+
import { APP_VERSION, DOCKER_REPO } from 'utils/constants';
1616
import { rm } from 'utils/files';
1717
import {
1818
createBitcoindNetworkNode,
@@ -21,6 +21,7 @@ import {
2121
createLndNetworkNode,
2222
createNetwork,
2323
filterCompatibleBackends,
24+
getMissingImages,
2425
getOpenPorts,
2526
importNetworkFromZip,
2627
OpenPorts,
@@ -488,39 +489,53 @@ const networkModel: NetworkModel = {
488489
network.status = status;
489490
}
490491
}),
491-
start: thunk(async (actions, networkId, { getState, injections, getStoreActions }) => {
492-
let network = getState().networks.find(n => n.id === networkId);
493-
if (!network) throw new Error(l('networkByIdErr', { networkId }));
494-
const { id } = network;
495-
actions.setStatus({ id: id, status: Status.Starting });
496-
try {
497-
// make sure the node ports are available
498-
const ports = await getOpenPorts(network);
499-
if (ports) {
500-
// at least one port was updated. save the network & composeFile
501-
actions.updateNodePorts({ id, ports });
502-
// re-fetch the network with the updated ports
503-
network = getState().networks.find(n => n.id === networkId) as Network;
504-
await actions.save();
505-
await injections.dockerService.saveComposeFile(network);
492+
start: thunk(
493+
async (
494+
actions,
495+
networkId,
496+
{ getState, injections, getStoreState, getStoreActions },
497+
) => {
498+
let network = getState().networks.find(n => n.id === networkId);
499+
if (!network) throw new Error(l('networkByIdErr', { networkId }));
500+
const { dockerImages } = getStoreState().app;
501+
// make sure all non-Polar images are available
502+
const missingImages = getMissingImages(network, dockerImages).filter(
503+
i => !i.startsWith(DOCKER_REPO),
504+
);
505+
if (missingImages.length) {
506+
throw new Error(`${l('missingImages')}: ${missingImages.join(', ')}`);
506507
}
507-
// start the docker containers
508-
await injections.dockerService.start(network);
509-
// update the list of docker images pulled since new images may be pulled
510-
await getStoreActions().app.getDockerImages();
511-
// set the status of only the network to Started
512-
actions.setStatus({ id, status: Status.Started, all: false });
513-
// wait for nodes to startup before updating their status
514-
await actions.monitorStartup([
515-
...network.nodes.lightning,
516-
...network.nodes.bitcoin,
517-
]);
518-
} catch (e) {
519-
actions.setStatus({ id, status: Status.Error });
520-
info(`unable to start network '${network.name}'`, e.message);
521-
throw e;
522-
}
523-
}),
508+
const { id } = network;
509+
actions.setStatus({ id: id, status: Status.Starting });
510+
try {
511+
// make sure the node ports are available
512+
const ports = await getOpenPorts(network);
513+
if (ports) {
514+
// at least one port was updated. save the network & composeFile
515+
actions.updateNodePorts({ id, ports });
516+
// re-fetch the network with the updated ports
517+
network = getState().networks.find(n => n.id === networkId) as Network;
518+
await actions.save();
519+
await injections.dockerService.saveComposeFile(network);
520+
}
521+
// start the docker containers
522+
await injections.dockerService.start(network);
523+
// update the list of docker images pulled since new images may be pulled
524+
await getStoreActions().app.getDockerImages();
525+
// set the status of only the network to Started
526+
actions.setStatus({ id, status: Status.Started, all: false });
527+
// wait for nodes to startup before updating their status
528+
await actions.monitorStartup([
529+
...network.nodes.lightning,
530+
...network.nodes.bitcoin,
531+
]);
532+
} catch (e) {
533+
actions.setStatus({ id, status: Status.Error });
534+
info(`unable to start network '${network.name}'`, e.message);
535+
throw e;
536+
}
537+
},
538+
),
524539
stop: thunk(async (actions, networkId, { getState, injections }) => {
525540
const network = getState().networks.find(n => n.id === networkId);
526541
if (!network) throw new Error(l('networkByIdErr', { networkId }));

0 commit comments

Comments
 (0)