after some more thought:
* If app moves to another location, user has to remember to move all this config
* It's not really associated with an app. It's to do with the domain info
* We can put some hints in the UI if app is missing.
part of #703
the main reason this is under app and not domain is because it let's
the user know that an app has to be installed for the whole thing to work.
part of #703
the get() query was wrong when we had multiple port bindings.
we did apps JOIN X JOIN Y JOIN Z. This will return apps times x times y times z rows.
this just accidentally worked in the past. when we have multiple mounts,
we get duplicate values now.
the fix is do the joins separately and then merge them together.
an alternate approach to this mega query is to SET TRANSACTION SERIALIZABLE and do
multiple selects. but that requires database.js support which is a bit of work (and not
sure how it works with "connections").
We removed httpPort with the assumption that docker allocated IPs
and kept them as long as the container is around. This turned out
to be not true because the IP changes on even container restart.
So we now allocate IPs statically. The iprange makes sure we don't
overlap with addons and other CI app or JupyterHub apps.
https://github.com/moby/moby/issues/6743https://github.com/moby/moby/pull/19001
we can just use container IP instead of all this httpPort exporting magic.
this is also required for exposing httpPaths feature (we have to otherwise
have multiple httpPorts).
* Do not allow scheduling tasks in error state
* Only repair is allowed in error state
* Use the error object to track what to 'repair' (like the lastState)
* If uninstall failed, repair will do uninstall
* If move dir failed, repair will do move dir
App operations can only be done in 'installed' or 'error' state.
If some other operation is in progress, you have to cancel it first.
This guarantees that the old app command got killed.