Skip to content

Commit b8c932d

Browse files
committed
20220708 Node-RED - master branch - PR 1 of 2 - part 2
Fixes `nodered_list_installed_nodes.sh`. Now relies on `npm` running inside the container to discover what's installed where. Documentation describing use of `/data` on `npm` calls turns out to be ineffective. The solution is to set the working directory on the `docker exec` call. Following on from a discussion on Discord [starting here](https://discord.com/channels/638610460567928832/638610461109256194/994818372439113838), it was obviously confusing for the documentation to be discussing "nodes" when `npm` can be used to install a variety of components. Documentation adjusted to clarify this. Signed-off-by: Phill Kelley <[email protected]>
1 parent a7a8485 commit b8c932d

File tree

2 files changed

+116
-118
lines changed

2 files changed

+116
-118
lines changed

docs/Containers/Node-RED.md

Lines changed: 77 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ You choose add-on nodes from a supplementary menu. We recommend accepting the de
5454
Key points:
5555

5656
* Under new menu, you must press the right arrow to access the supplementary menu. Under old menu, the list of add-on nodes is displayed automatically.
57-
* Do not be concerned if you can't find an add-on node you need in the list. You can also add nodes via Manage Palette once Node-RED is running. See [node management](#nodeManagement).
57+
* Do not be concerned if you can't find an add-on node you need in the list. You can also add nodes via Manage Palette once Node-RED is running. See [component management](#componentManagement).
5858

5959
Choosing add-on nodes in the menu causes the *Dockerfile* to be created.
6060

@@ -256,7 +256,7 @@ To communicate with your Raspberry Pi's GPIO you need to do the following:
256256
$ sudo apt install pigpio python-pigpio python3-pigpio
257257
```
258258

259-
2. Install the `node-red-node-pi-gpiod` node. See [node management](#nodeManagement). It allows you to connect to multiple Pis from the same Node-RED service.
259+
2. Install the `node-red-node-pi-gpiod` node. See [component management](#componentManagement). It allows you to connect to multiple Pis from the same Node-RED service.
260260
3. Make sure that the `pigpdiod` daemon is running. The recommended method is listed [here](https://github.com/node-red/node-red-nodes/tree/master/hardware/pigpiod). In essence, you need to:
261261

262262
- Use `sudo` to edit `/etc/rc.local`;
@@ -991,71 +991,78 @@ For example, suppose you wanted to pin to Node-RED version 2.2.2 with `node.js`
991991

992992
Changing a pinned version and rebuilding *may* result in a new *base* image being downloaded from *DockerHub*.
993993

994-
## Node management { #nodeManagement }
994+
## Component management { #componentManagement }
995995

996-
### Installing nodes { #addNodes }
996+
### via Dockerfile { #viaDockerfile }
997997

998-
You can install nodes by:
998+
You can install components by adjusting the Node-RED *Dockerfile*. This can be done by:
999999

1000-
1. Adjusting the Node-RED *Dockerfile*. This can be done by:
1000+
* Running the IOTstack menu and changing the selected Node-RED nodes; or
1001+
* Editing your Node-RED *Dockerfile* using a text editor.
10011002

1002-
* Running the IOTstack menu and changing the selected Node-RED nodes; or
1003-
* Editing your Node-RED *Dockerfile* using a text editor.
1003+
Using the IOTstack menu limits your choice of components to those presented in the menu. Editing the *Dockerfile* with a text editor is more flexible but carries the risk that your changes could be lost if you subsequently use the menu method.
10041004

1005-
Using the IOTstack menu limits your choice of nodes to those presented in the menu. Editing the *Dockerfile* with a text editor is more flexible but carries the risk that your changes could be lost if you subsequently use the menu method.
1005+
To apply changes made to your *Dockerfile*, run the [re-building the local Node-RED image](#rebuildNodeRed) commands.
10061006

1007-
To apply changes made to your *Dockerfile*, run the [re-building the local Node-RED image](#rebuildNodeRed) commands.
1007+
### via Manage Palette { #viaDockerfile }
10081008

1009-
2. Adding, removing or updating nodes in Manage Palette. Node-RED will remind you to restart Node-RED and that is something you have to do by hand:
1009+
You can add, remove or update components in Manage Palette. Node-RED will remind you to restart Node-RED and that is something you have to do by hand:
10101010

1011-
``` console
1012-
$ cd ~/IOTstack
1013-
$ docker-compose restart nodered
1014-
```
1011+
``` console
1012+
$ cd ~/IOTstack
1013+
$ docker-compose restart nodered
1014+
```
10151015
1016-
Note:
1016+
Note:
10171017

1018-
* Some users have reported misbehaviour from Node-RED if they do too many iterations of:
1018+
* Some users have reported misbehaviour from Node-RED if they do too many iterations of:
1019+
1020+
- make a change in Manage Palette
1021+
- restart Node-RED
10191022
1020-
``` console
1021-
[make a single change in Manage Palette]
1022-
$ docker-compose restart nodered
1023+
It is better to make **all** the changes you intend to make, and only *then* restart Node-RED.
10231024

1024-
[make a single change in Manage Palette]
1025-
$ docker-compose restart nodered
1026-
1027-
1028-
```
1025+
### via `npm` { #viaNPM }
10291026

1030-
It is better to:
1027+
You can also run `npm` inside the container to install any component that could be installed by `npm` in a non-container environment. This is the basic syntax:
10311028

1032-
``` console
1033-
[do ALL your Manage Palette changes]
1034-
$ docker-compose restart nodered
1035-
```
1029+
``` console
1030+
$ cd ~/IOTstack
1031+
$ docker exec -w /data nodered npm «command» «arguments…»
1032+
$ docker-compose restart nodered
1033+
```
1034+
1035+
Examples:
10361036

1037-
3. Installing nodes inside the container via npm:
1037+
* To add the "find my iphone" node:
10381038

10391039
``` console
1040-
$ docker exec -it nodered bash
1041-
# cd /data
1042-
# npm install «node-name» /data
1043-
# exit
1044-
$ cd ~/IOTstack
1040+
$ docker exec -w /data nodered npm install find-my-iphone-node
10451041
$ docker-compose restart nodered
10461042
```
1043+
1044+
* To remove the "find my iphone" node:
1045+
1046+
``` console
1047+
$ docker exec -w /data nodered npm uninstall find-my-iphone-node
1048+
$ docker-compose restart nodered
1049+
```
1050+
1051+
Note:
10471052

1048-
Note:
1049-
1050-
* You **must** put the `/data` onto the end of the `npm install` command. Any formula you find on the web will not include this. You have to remember to do it yourself!
1051-
* See also the note above about restarting too frequently.
1052-
* You can use this approach if you need to force the installation of a specific version (which you don't appear to be able to do in Manage Palette). For example, to install version 4.0.0 of the "moment" node:
1053+
* You **must** include `-w /data` on each command. Any formula you find on the web will not include this. You have to remember to do it yourself!
1054+
* Many web examples include the `--save` flag on the `npm` command. That flag is not needed (it is ignored because the behaviour it used to control has been the default since NPM version 5. Node-RED containers have been using NPM version 6 for some time.
1055+
* See also the note above about restarting too frequently.
1056+
* You can use this approach if you need to force the installation of a specific version (which you don't appear to be able to do in Manage Palette). For example, to install version 4.0.0 of the "moment" node:
10531057

1054-
``` console
1055-
# npm install [email protected] /data
1056-
```
1058+
``` console
1059+
$ docker exec -w /data nodered npm install [email protected]
1060+
$ docker-compose restart nodered
1061+
```
1062+
1063+
### Comparison of methods { #viaWhich }
10571064

1058-
There is no real difference between the methods. Some nodes (eg "node-red-contrib-generic-ble" and "node-red-node-sqlite") **must** be installed by *Dockerfile* but the only way of finding out if a node **must** be installed via *Dockerfile* is to try Manage Palette and find that it doesn't work.
1065+
In terms of outcome, there is no real difference between the various methods. However, some nodes (eg "node-red-contrib-generic-ble" and "node-red-node-sqlite") **must** be installed by *Dockerfile*. The only way of finding out if a component **must** be installed via *Dockerfile* is to try Manage Palette and find that it doesn't work.
10591066

10601067
Aside from the exception cases that require *Dockerfile* or where you need to force a specific version, it is quicker to install nodes via Manage Palette and applying updates is a bit easier too. But it's really up to you.
10611068

@@ -1066,62 +1073,44 @@ If you're wondering about "backup", nodes installed via:
10661073

10671074
Basically, if you're running IOTstack backups then your add-on nodes will be backed-up.
10681075

1069-
### Node precedence { #nodePrecedence }
1076+
### Component precedence { #componentPrecedence }
10701077

1071-
Add-on nodes that are installed via *Dockerfile* wind up at the **internal** path:
1078+
Components that are installed via *Dockerfile* wind up at the **internal** path:
10721079

10731080
```
1074-
/usr/src/node-red/node_modules
1081+
/usr/src/node-red
10751082
```
10761083

1077-
Add-on nodes installed via Manage Palette wind up at the **external** path:
1084+
Components installed via Manage Palette or `docker exec -w /data` wind up at the **internal** path:
10781085

10791086
```
1080-
~/IOTstack/volumes/nodered/data/node_modules
1081-
```
1082-
1083-
The *Compose* file volumes mapping:
1084-
1085-
``` yaml
1086-
./volumes/nodered/data:/data
1087+
/data
10871088
```
10881089

1089-
implies that add-on nodes installed via Manage Palette are made available to Node-RED at the **internal** path:
1090+
which is the same as the **external** path:
10901091

10911092
```
1092-
/data/node_modules
1093+
~/IOTstack/volumes/nodered/data
10931094
```
10941095

1095-
Because there are two places, this invites the question of what happens if a given node is installed in both? The answer is that add-ons installed at:
1096+
Because there are two places, this invites the question of what happens if a given component is installed in both? The answer is that components installed in `/data` take precedence.
10961097

1097-
```
1098-
/data/node_modules
1099-
```
1100-
1101-
take precedence over those installed at:
1102-
1103-
```
1104-
/usr/src/node-red/node_modules
1105-
```
1106-
1107-
Or, to put it more simply: in any contest, Manage Palette prevails over *Dockerfile*.
1098+
Or, to put it more simply: in any contest between methods, *Dockerfile* comes last.
11081099

11091100
### Resolving node duplication { #fixDuplicateNodes }
11101101

1111-
Sometimes, even when you are 100% certain that **you** didn't do it, an add-on node will turn up in both places. There is probably some logical reason for this but I don't know what it is.
1112-
1113-
The problem this creates is that a later version of an add-on node installed via *Dockerfile* will be blocked by the presence of an older version of that node in:
1102+
Sometimes, even when you are 100% certain that **you** didn't do it, a component will turn up in both places. There is probably some logical reason for this but I don't know what it is.
11141103

1115-
```
1116-
~/IOTstack/volumes/nodered/data/node_modules
1117-
```
1104+
The problem this creates is that a later version of a component installed via *Dockerfile* will be blocked by the presence of an older version of that component installed by a different method.
11181105

11191106
The `nodered_list_installed_nodes.sh` script helps discover when this situation exists. For example:
11201107

11211108
``` console
1122-
$ ~/IOTstack/scripts/nodered_list_installed_nodes.sh
1109+
$ nodered_list_installed_nodes.sh
1110+
1111+
Fetching list of candidates installed via Dockerfile
11231112
1124-
Nodes installed by Dockerfile INSIDE the container at /usr/src/node-red/node_modules
1113+
Components built into the image (via Dockerfile)
11251114
ACTIVE: node-red-admin
11261115
ACTIVE: node-red-configurable-ping
11271116
ACTIVE: node-red-contrib-boolean-logic
@@ -1134,13 +1123,16 @@ Nodes installed by Dockerfile INSIDE the container at /usr/src/node-red/node_mod
11341123
ACTIVE: node-red-node-sqlite
11351124
ACTIVE: node-red-node-tail
11361125
1137-
Nodes installed by «Manage Palette» OUTSIDE the container at /home/pi/IOTstack/volumes/nodered/data/node_modules
1138-
node-red-contrib-boolean-logic-ultimate
1139-
node-red-contrib-chartjs
1140-
node-red-node-email
1141-
node-red-contrib-md5
1142-
node-red-contrib-moment
1143-
node-red-contrib-pushsafer
1126+
Fetching list of candidates installed via Manage Palette or npm
1127+
1128+
Components in persistent store at
1129+
/home/pi/IOTstack/volumes/nodered/data/node_modules
1130+
node-red-contrib-boolean-logic-ultimate
1131+
node-red-contrib-chartjs
1132+
node-red-node-email
1133+
node-red-contrib-md5
1134+
node-red-contrib-moment
1135+
node-red-contrib-pushsafer
11441136
```
11451137

11461138
Notice how `node-red-node-email` appears in both lists. To fix this problem:
Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,47 @@
11
#!/usr/bin/env bash
22

3-
INTERNAL="/usr/src/node-red/node_modules"
4-
EXTERNAL="$HOME/IOTstack/volumes/nodered/data/node_modules"
5-
6-
echo -e "\nNodes installed by Dockerfile INSIDE the container at $INTERNAL"
7-
8-
CANDIDATES=$(docker exec nodered bash -c "ls -1d $INTERNAL/node-red-*")
9-
10-
for C in $CANDIDATES; do
11-
12-
NODE=$(basename "$C")
13-
14-
# is a node of the same name also present externally
15-
if [ -d "$EXTERNAL/$NODE" ] ; then
16-
17-
# yes! the internal node is blocked by the external node
18-
echo " BLOCKED: $NODE"
19-
20-
else
21-
22-
# no! so that means it's active
23-
echo " ACTIVE: $NODE"
24-
3+
# where Dockerfile installs components INSIDE the container
4+
DOCKERFILE="/usr/src/node-red"
5+
6+
# paths to the persistent store
7+
PERSISTENT_INTERNAL="/data"
8+
PERSISTENT_EXTERNAL="$HOME/IOTstack/volumes/nodered/data"
9+
10+
# the folder in each case containing node modules
11+
MODULES="node_modules"
12+
13+
# fetch what npm knows about components that form part of the image
14+
echo -e "\nFetching list of candidates installed via Dockerfile"
15+
CANDIDATES=$(docker exec nodered bash -c "cd \"$DOCKERFILE\" ; npm list --depth=0 --parseable")
16+
17+
# report
18+
echo -e "\nComponents built into the image (via Dockerfile)"
19+
PARENT=$(basename "$DOCKERFILE")
20+
for CANDIDATE in $CANDIDATES; do
21+
COMPONENT=$(basename "$CANDIDATE")
22+
if [ "$COMPONENT" != "$PARENT" ] ; then
23+
if [ -d "$PERSISTENT_EXTERNAL/$MODULES/$COMPONENT" ] ; then
24+
# yes! the internal node is blocked by the external node
25+
echo " BLOCKED: $COMPONENT"
26+
else
27+
# no! so that means it's active
28+
echo " ACTIVE: $COMPONENT"
29+
fi
2530
fi
26-
2731
done
2832

29-
echo -e "\nNodes installed by Manage Palette OUTSIDE the container at $EXTERNAL"
30-
31-
CANDIDATES=$(ls -1d "$EXTERNAL/node-red-"*)
32-
33-
for C in $CANDIDATES; do
34-
35-
NODE=$(basename "$C")
36-
37-
echo " $NODE"
38-
33+
# fetch what npm knows about components that are in the persistent store
34+
echo -e "\nFetching list of candidates installed via Manage Palette or npm"
35+
CANDIDATES=$(docker exec nodered bash -c "cd \"$PERSISTENT_INTERNAL\" ; npm list --depth=0 --parseable")
36+
37+
# report
38+
echo -e "\nComponents in persistent store at\n $PERSISTENT_EXTERNAL/$MODULES"
39+
PARENT=$(basename "$PERSISTENT_INTERNAL")
40+
for CANDIDATE in $CANDIDATES; do
41+
COMPONENT=$(basename "$CANDIDATE")
42+
if [ "$COMPONENT" != "$PARENT" ] ; then
43+
echo " $COMPONENT"
44+
fi
3945
done
4046

4147
echo ""

0 commit comments

Comments
 (0)