Repository: jupyterhub/jupyterhub

Issue:
--generate-config fails since 1.1.0
**Describe the bug**

The function `--generate-config` doesn't work as expected with the release of 1.1.0. Jupyterhub complains about the missing config file, which should be generated. We execute the steps in a Packer build process, which worked until the upgrade of jupyterhub from 1.0.0 to 1.1.0.

The executed command is even listed in the -h explanation, so I'm pretty confident it should work:

```sh
[user@ip-1-1-1-1 ~]$ /opt/anaconda3/bin/jupyterhub -h
Start a multi-user Jupyter Notebook server
[..]

Examples
--------

    generate default config file:
    
        jupyterhub --generate-config -f /etc/jupyterhub/jupyterhub_config.py
    
[...]
```

Please don't hit me if conda or amazon linux may introduce this error, but I personally don't think so.

**To Reproduce**

Just execute jupyterhub with *--generate-config*. Installation has been done via conda. Execute the following commands on a clean linux/centos/amazonLinux1.

```sh
$ wget https://repo.continuum.io/archive/Anaconda3-2019.10-Linux-x86_64.sh -O /tmp/Anaconda3-Linux-x86_64.sh
$ sudo sh /tmp/Anaconda3-Linux-x86_64.sh -b -p /opt/anaconda3
$ sudo /opt/anaconda3/bin/conda config --add channels 'conda-forge'
$ sudo /opt/anaconda3/bin/conda install -y -c conda-forge jupyterhub",
$ sudo /opt/anaconda3/bin/jupyterhub --generate-config -f /etc/jupyterhub/jupyterhub_config.py
ERROR: Failed to find specified config file: /etc/jupyterhub/jupyterhub_config.py
```

**Expected behavior**

The config file should be generated. Failing with "Failed to find specified config file" doesn't make sense.

**Compute Information**

 - Installation is usually performed within a packer build, but problem can be reproduced manually.

```sh
[user@ip-1-1-1-1 ~]$ cat /etc/issue
Amazon Linux AMI release 2018.03
[user@ip-1-1-1-1 ~]$ sudo /opt/anaconda3/bin/jupyterhub --version
1.1.0
```





Discussion:
I've reproduced this in a plain virtualenv. This is a bug when the output filename is *not* `jupyterhub_config.py`.

```
$ python3 --version
Python 3.7.5

$ python3 -m venv jupyterhub-test

$ ./jupyterhub-test/bin/pip install jupyterhub
...
Successfully installed Mako-1.1.1 MarkupSafe-1.1.1 SQLAlchemy-1.3.12 alembic-1.3.2 async-generator-1.10 attrs-19.3.0 certifi-2019.11.28 certipy-0.1.3 cffi-1.13.2 chardet-3.0.4 cryptography-2.8 decorator-4.4.1 entrypoints-0.3 idna-2.8 importlib-metadata-1.4.0 ipython-genutils-0.2.0 jinja2-2.10.3 jsonschema-3.2.0 jupyter-telemetry-0.0.4 jupyterhub-1.1.0 more-itertools-8.1.0 oauthlib-3.1.0 pamela-1.0.0 prometheus-client-0.7.1 pycparser-2.19 pyopenssl-19.1.0 pyrsistent-0.15.7 python-dateutil-2.8.1 python-editor-1.0.4 python-json-logger-0.1.11 requests-2.22.0 ruamel.yaml-0.16.6 ruamel.yaml.clib-0.2.0 six-1.14.0 tornado-6.0.3 traitlets-4.3.3 urllib3-1.25.8 zipp-2.0.0

$ rm -f jupyterhub_config.py

$ ./jupyterhub-test/bin/jupyterhub --generate-config -f jupyterhub_config.py
Writing default config to: jupyterhub_config.py

$ rm -f jupyterhub_config.py

$ ./jupyterhub-test/bin/jupyterhub --generate-config -f jupyterhub_config2.py
ERROR: Failed to find specified config file: jupyterhub_config2.py
```

I suspect this PR by my has caused this somehow: #2824.

Yepp. It seems that the `-f` flag is the same as setting c.JupyterHub.config_file.

```python
common_aliases = {
    'log-level': 'Application.log_level',
    'f': 'JupyterHub.config_file',
    'config': 'JupyterHub.config_file',
    'db': 'JupyterHub.db_url',
}
```

And that the `config_file` traitlet has a validation logic on it to error directly if a config_file is specified that does not exist since of #2824. But, it should not error on missing file when --generate-config is passed, but then perhaps the opposite should happen.

Resolving patch:
diff --git a/jupyterhub/app.py b/jupyterhub/app.py
--- a/jupyterhub/app.py
+++ b/jupyterhub/app.py
@@ -316,7 +316,7 @@ def _load_classes(self):
 
     @validate("config_file")
     def _validate_config_file(self, proposal):
-        if not os.path.isfile(proposal.value):
+        if not self.generate_config and not os.path.isfile(proposal.value):
             print(
                 "ERROR: Failed to find specified config file: {}".format(
                     proposal.value


Test patch: