diff --git a/.gitignore b/.gitignore index e30f84253..69fd43812 100644 --- a/.gitignore +++ b/.gitignore @@ -111,3 +111,5 @@ helm.txt travis helm-chart/travis-binder.yaml +# Federation data page +doc/federation/data-federation.txt \ No newline at end of file diff --git a/doc/_static/custom.css b/doc/_static/custom.css index 1ad0da5ba..1ddaa6ffe 100644 --- a/doc/_static/custom.css +++ b/doc/_static/custom.css @@ -33,3 +33,44 @@ img.logo { .prev-next-top { margin-bottom: 1em; } + + +/* Federation page CSS */ +.contrib_entry p { + margin: 2px; + text-align: center; +} + +p.contrib_affiliation { + font-size: .7em; + font-weight: bold; +} + +.contribs_text { + font-size: .8em; +} + +.contrib_entry p.contribs { + float: left; + margin: 0px; +} + +td.contrib_entry { + width: 150px; + height: 200px; + padding: 1em !important; + vertical-align: top; + text-align: center; +} + +td.contrib_entry a { + text-decoration: none; +} + +td.contrib_entry img { + width: 100%; +} + +table.contributors { + margin: 0px auto; +} \ No newline at end of file diff --git a/doc/conf.py b/doc/conf.py index 37aa20725..2ac945b9f 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -18,6 +18,7 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. # import os +import os.path as op import sys import requests curdir = os.path.dirname(__file__) @@ -209,3 +210,8 @@ # -- Add custom CSS ---------------------------------------------- def setup(app): app.add_stylesheet('https://gitcdn.link/repo/jupyterhub/binder/master/doc/_static/custom.css') + +# -- Run Federation script ---------------------------------------------- +from subprocess import run +cmd = ["python", op.join('script', 'gen_federation.py')] +run(cmd) \ No newline at end of file diff --git a/doc/doc-requirements.txt b/doc/doc-requirements.txt index a2c54dd90..96b78c0a8 100644 --- a/doc/doc-requirements.txt +++ b/doc/doc-requirements.txt @@ -4,6 +4,8 @@ recommonmark==0.4.0 sphinx-copybutton alabaster_jupyterhub traitlets +pandas +ruamel.yaml # install BinderHub dependencies. We manually list them here because some # dependencies (like pycurl) can't be installed on ReadTheDocs and aren't # needed to build the docs. diff --git a/doc/federation/data-federation.yml b/doc/federation/data-federation.yml new file mode 100644 index 000000000..0c9caa096 --- /dev/null +++ b/doc/federation/data-federation.yml @@ -0,0 +1,13 @@ +- url_binderhub: https://gke.mybinder.org + logo: https://binderhub.readthedocs.io/en/latest/_static/logo.png + funded_by: Google Cloud Platform + funded_by_link: https://cloud.google.com/ + run_by: The Binder Team + run_by_link: https://jupyterhub-team-compass.readthedocs.io/en/latest/team.html#binder-team + +- url_binderhub: https://ovh.mybinder.org + logo: https://www.ovh.com/fr/images/logos/logo-ovh-twitter.jpg + funded_by: OVH + funded_by_link: https://www.ovh.com/world/ + run_by: The OVH Team + run_by_link: https://www.ovh.com/world/ diff --git a/doc/federation/federation.rst b/doc/federation/federation.rst new file mode 100644 index 000000000..d38c243f2 --- /dev/null +++ b/doc/federation/federation.rst @@ -0,0 +1,129 @@ +.. _federation/federation: + +======================== +The BinderHub Federation +======================== + +While it may seem like ``mybinder.org`` is a single website, it is +in fact a **federation** of teams that deploy public BinderHubs to serve +the community. This page lists the BinderHubs that currently help +power ``mybinder.org``. + +Visiting ``mybinder.org`` will randomly redirect you to one +of the following BinderHubs. + +.. note:: + + If your organization is interested in becoming part of the BinderHub + federation, check out :ref:`federation/joining`. + +.. _federation/federation-list: + +Members of the BinderHub Federation +=================================== + +Here is a list of the current members of the BinderHub federation: + +.. include:: data-federation.txt + + +.. _federation/joining: + +Joining the BinderHub Federation +================================ + +Behind ``mybinder.org`` is a **federation of BinderHubs**. This means that there +are several independent hubs that each serve a fraction of the traffic +created by people clicking links pointing to ``mybinder.org``. Anyone +(a company, university or individual) is welcome to deploy a BinderHub +that forms part of the federation. + +Adding a new BinderHub to the federation requires a mix of two kinds of +resources: compute and human power to operate the hub. The two extremes +of this mixture are: + +* You donate compute power that the ``mybinder.org`` team + **has full control over**, which means you don't have to be involved in day to + day operations +* You donate compute power over which the ``mybinder.org`` team **does not** + have full control which means you are also responsible for day to day + operations of the BinderHub. + +.. _federation/things-to-consider: + +Things to consider when deciding to join the Binder federation +-------------------------------------------------------------- + +If you're interested in joining the federation of BinderHubs, consider the +following questions: + +1. **How much time will this take?** Answering this question depends largely + on how comfortable you are deploying and maintaining your own BinderHub. + If you are fairly comfortable, it won't take much time. Otherwise, it may + be a good idea to gain some experience in running a BinderHub first - + perhaps by helping with the ``mybinder.org`` deployment! +2. **Is there any kind of service agreement?** Not really. We expect that + any member of the BinderHub federation will be committed to keeping their + BinderHub running with a reasonable uptime, but we don't have any legal + framework to enforce this. Use your best judgment when deciding if you'd + like to join the BinderHub federation - if you can confidently say your + BinderHub will be up the large majority of the time, then that's fine. +3. **What kind of cloud resources would I need?** This depends on how many + you have :-) We can increase or decrease the percentage of ``mybinder.org`` + traffic that goes to your BinderHub based on what you can handle. +4. **I'm still interested, what should I do next to join?** If you'd still + like to join the BinderHub federation, see :ref:`federation/how-to-join`. + + +.. _federation/how-to-join: + +How to join the BinderHub Federation +------------------------------------ + +If you've read through :ref:`federation/things-to-consider` and would +like to join the BinderHub federation, please reach out to the +Binder team by opening an issue at `the mybinder.org repository `_. +Mention that you'd like to join the federation, what kind of computational +resources you have, and what kind of human resources you have for maintaining +the BinderHub deployment. + +The next step is for you to tell us where your BinderHub lives. We'll assign +a sub-domain of ``mybinder.org`` (e.g. ``ovh.mybinder.org``) that points to +your BinderHub. Finally, we'll change the routing configuration so that +some percentage of traffic to ``mybinder.org`` is directed to your BinderHub! +The last step is to tell everybody how awesome you are, and to add your +deployment to :ref:`federation/federation-list` page. + +.. _federation/faq: + +The BinderHub Federation FAQ +============================ + +Can I deploy a BinderHub *both* for the federation and for my own community? +---------------------------------------------------------------------------- + +Yes! BinderHub can be deployed either as a public service (such as at mybinder.org), +or for a more restricted community. Serving a smaller community means you can +expose users to more resources or allow access to privileged data. + +If you'd like to both serve a more specific population of users *and* support the +public mybinder.org federation, we recommend running two BinderHubs in parallel +with one another. You can do this on the same Kubernets cluster if you wish, and +you'd configure each BinderHub according to the resources and access that you +want to provide. + +Who is currently in the BinderHub federation? +--------------------------------------------- + +The current list of BinderHubs that are contributing to mybinder.org can be +found at :ref:`federation/federation-list`. + +Does the BinderHub federation share Docker images? +-------------------------------------------------- + +Currently, the federation does *not* share Docker images for repositories. +This means that you might have to build your repository a few times (one for +each BinderHub that serves your images). We know that this adds some extra +waiting for many folks, and if you have any suggestions for how we can speed +up this process please `open an issue `_ +in the BinderHub repository! \ No newline at end of file diff --git a/doc/index.rst b/doc/index.rst index b1e38698c..1b63e694a 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -70,6 +70,7 @@ in the community have done. customizing authentication known-deployments + federation/federation BinderHub Developer and Architecture Documentation ================================================== diff --git a/doc/script/gen_federation.py b/doc/script/gen_federation.py new file mode 100644 index 000000000..41845eb66 --- /dev/null +++ b/doc/script/gen_federation.py @@ -0,0 +1,56 @@ +"""Generate HTML binderhubs tables for team pages +""" +import pandas as pd +import os +import os.path as op +from ruamel import yaml + +# Variables +N_PER_ROW = 4 + +# Code to generate the HTML grid +template_binderhub = '

{BINDERHUB_SUBDOMAIN}


Run by

{RUN_BY}


Funded by

{FUNDED_BY}

' + + +def _generate_binderhubs(binderhubs): + """Generate an HTML list of BinderHubs, given a dataframe of their information.""" + s = ['', ''] + for ix, binderhub in binderhubs.iterrows(): + if ix % N_PER_ROW == 0 and ix != 0: + s += [''] + + # Add user + format_dict = dict( + URL_BINDERHUB=binderhub["url_binderhub"], + BINDERHUB_SUBDOMAIN=binderhub["url_binderhub"].split("//")[-1], + LOGO=binderhub["logo"], + RUN_BY=binderhub["run_by"], + RUN_BY_LINK=binderhub["run_by_link"], + FUNDED_BY=binderhub["funded_by"], + FUNDED_BY_LINK=binderhub["funded_by_link"], + ) + + # Render + s += [template_binderhub.format(**format_dict)] + s += ["
"] + final_text = [".. raw:: html", ""] + for line in s: + final_text += [" " + line] + final_text = "\n".join(final_text) + return final_text + + +# Run the function +path_data = op.join( + op.dirname(op.abspath(__file__)), "..", "federation", "data-federation.yml" +) +yaml = yaml.YAML() + +with open(path_data, "r") as ff: + data = yaml.load(ff) + +binderhubs = pd.DataFrame(data) +table = _generate_binderhubs(binderhubs) +new_name = os.path.splitext(path_data)[0] +with open(new_name + ".txt", "w") as ff: + ff.write(table)