As part of investigating a bug, I wanted to do some independent verification of the charm content by doing a direct download via curl. Juju doesn’t make that particularly easy, because it does a fair bit of validation, and getting the URL formatted correctly was a bit of work. I had to instrument my agents and controller to work out what the right things were, and I ended up getting to this:
# You can get this value from the log line about "downloading"
charmurl="ch:amd64/jammy/github-runner-140"
filename="/tmp/${charmurl##*/}.zip"
cd /var/lib/juju/agents/unit*
# all these values are read from agent.conf
user=`awk '$1 == "tag:" {print($2)}' agent.conf`
password=`awk '$1 == "apipassword:" {print($2)}' agent.conf`
address=`grep -A1 apiaddresses agent.conf | awk '$1 == "-" {print($2)}'`
model=`awk '$1 == "model:" {print($2)}' agent.conf | sed 's/-/\//'`
curl -G --insecure \
-o ${filename} \
--user "${user}:${password}" \
--data-urlencode "file=*" \
--data-urlencode "url=${charmurl}" \
"https://${address}/${model}/charms"
# and test that it downloaded correctly
unzip -t ${filename}
Juju uses basic auth, using tag names as the ‘username’ and the password that is stored in agent.conf. The API address is just an https address being served on a non-standard port (typically 17070). The above code is written assuming you only have 1 controller address.
The URL to GET a charm is found at:
https://$CONTROLLERADDRES:$CONTROLLERPORT/model/$MODELUUID/charms
With URL parameters of “file=*
” and “url=$CHARMURL
”. In the above script I use --data-urlencode
to make sure those get escaped correctly (and -G to force it to do a GET instead of a POST request).
The final URL looks something like this:
https://10.139.162.57:17070/model/fca90071-fa5d-4fae-811f-5696cac9bfb2/charms?file=%2A&url=ch%3Aamd64%2Fjammy%2Fgithub-runner-140