Skip to content

Commit

Permalink
Merge pull request #1 from icteam-spa/user_based_spawning
Browse files Browse the repository at this point in the history
FilteredSpawning
  • Loading branch information
Luke035 authored Dec 18, 2017
2 parents ab52e8d + 5bb2704 commit e96a87e
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ configuration of Spawner classes while permitting:
* configuration of Spawner classes that don't natively implement `options_form`
* administrator control of allowed configuration changes
* runtime choice of which Spawner backend to launch

FilteredSpawner allows the definition of profiles that can be assigned only to authenticated users belonging to a specific set of groups.Based over the original ProfilesSpawner it exploits a specific additional configuration profile parameter to specify the set of allowed groups or a * wildcard for enabling that specific profile for all the users


### Example

Expand Down Expand Up @@ -72,6 +75,29 @@ running as a local process or one of two different Docker Images to run within `
]
```

<b>FilteredSpawner</b> example
```python
c.JupyterHub.spawner_class = 'wrapspawner.FilteredSpawner'
c.Spawner.http_timeout = 120
#------------------------------------------------------------------------------
# ProfilesSpawner configuration
#------------------------------------------------------------------------------
# List of profiles to offer for selection. Signature is:
# List(Tuple( Unicode, Unicode, Type(Spawner), Dict, Unicode ))
# corresponding to profile display name, unique key, Spawner class,
# dictionary of spawner config options, comma separated list of authorized groups..
#
# The first three values will be exposed in the input_template as {display},
# {key}, and {type}
#
c.ProfilesSpawner.default_profiles = [
( "Sudospawner group1", 'sudospawner', 'sudospawner.SudoSpawner', {'cmd':['sudospawner-singleuser'], 'notebook_dir':''}, 'group1' ),
( "Sudospawner group2", 'sudospawner', 'sudospawner.SudoSpawner', {'cmd':['sudospawner-singleuser'], 'notebook_dir':''}, 'group2' ),
( "Global spawner", 'sudospawner', 'sudospawner.SudoSpawner', {'cmd':['sudospawner-singleuser'], 'notebook_dir':''}, '*' )

]
```

## History

These mechanisms originated as part of the [`batchspawner`](https://github.com/jupyterhub/batchspawner) package.
Expand Down
51 changes: 50 additions & 1 deletion wrapspawner/wrapspawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ class ProfilesSpawner(WrapSpawner):
help = """List of profiles to offer for selection. Signature is:
List(Tuple( Unicode, Unicode, Type(Spawner), Dict )) corresponding to
profile display name, unique key, Spawner class, dictionary of spawner config options.
The first three values will be exposed in the input_template as {display}, {key}, and {type}"""
)

Expand Down Expand Up @@ -220,6 +219,56 @@ def clear_state(self):
super().clear_state()
self.child_profile = ''

class FilteredSpawner(ProfilesSpawner):

"""ProfilesSpawner - leverages the Spawner options form feature to allow user-driven
configuration of Spawner classes while permitting:
1) configuration of Spawner classes that don't natively implement options_form
2) administrator control of allowed configuration changes
3) runtime choice of which Spawner backend to launch
"""
default_profiles = List(
trait = Tuple( Unicode(), Unicode(), Type(Spawner), Dict(), Unicode() ),
default_value = [],
config = True,
help = """List of profiles to offer in addition to docker images for selection. Signature is:
List(Tuple( Unicode, Unicode, Type(Spawner), Dict , Unicode)) corresponding to
profile display name, unique key, Spawner class, dictionary of spawner config options, comma separated list of authorized groups.
The first three values will be exposed in the input_template as {display}, {key}, and {type}"""
)

def get_user_groups(self):
import subprocess, sys
user = self.user.name
cmd_result = subprocess.Popen("groups "+user, shell=True, stdout=subprocess.PIPE).stdout.read()
#Get system default encoding
sys_encoding = sys.getdefaultencoding()
groups_list = cmd_result.decode(sys_encoding).split(':')[1].replace('\n', '').strip().split(' ')
return groups_list

def _user_profiles(self):
#Parse default_profiles and return a valid list
valid_profiles = []
for p in self.default_profiles:
#Parse authorized groups
#If authorized_groups contained the all wildcard, pass it without groups check
if p[4] == '*':
valid_profiles.append((p[0], p[1], p[2], p[3]))
#Check if profile is enabled for the user
authorized_groups = p[4].split(',')
user_groups = self.get_user_groups()
#Interesection between groups
groups_intersection = list(set(authorized_groups).intersection(user_groups))
#If groups_intersection is not empty, profile is authorized for user
if groups_intersection is not None and len(groups_intersection)>0:
valid_profiles.append((p[0], p[1], p[2], p[3]))
return valid_profiles

@property
def profiles(self):
#New profiles are default profiles in addition to user_based profiles
return self._user_profiles()

class DockerProfilesSpawner(ProfilesSpawner):

"""DockerProfilesSpawner - leverages ProfilesSpawner to dynamically create DockerSpawner
Expand Down

0 comments on commit e96a87e

Please sign in to comment.