Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a single init_container instead of overwriting init_containers #18

Merged
merged 1 commit into from
Jun 2, 2021

Conversation

MridulS
Copy link
Contributor

@MridulS MridulS commented Jun 2, 2021

Downstream users can add more initContainers

fixes #17

@g-braeunlich can you have a look?
Instead of the check for "project-manager" I am just appending it to the list of init_containers,
does this work for you? You can append another init_container in the subclassed spawner.

Downstream users can add more initContainers
@@ -195,13 +195,13 @@ def start(self):
# because start command is run as an ENTRYPOINT and initcontainer's command overwrites it
# But start command will be executed in notebook container (because we dont define a custom command for it),
# so change will take place there, and on user's side, there is no problem
self.init_containers = [{
self.init_containers.append({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, just not sure, but will start() be called only once per instance?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe so, a subclass with start

def start(self):
     self.init_containers.append(another_container_spec)
     super().start()

should work IMO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just am not sure, if it is possible that the same instance calls start() more than once. In this case, we would end up with 2 identical init containers. But if this is not possible, everything is fine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this should be okay (we can always revert this if something breaks :) )

This is how the subclassing would look like

In [1]: class A:  # KubeSpawner
   ...:     def __init__(self):
   ...:         self.a = list()
   ...:     def start(self):
   ...:         self.a.append('something')
   ...:

In [2]: class B(A):  # PersistentBinderSpawner
   ...:     def start(self):
   ...:         self.a.append('foo')
   ...:         super().start()
   ...:

In [3]: class C(B):
   ...:     def start(self):
   ...:         self.a.append('bar')
   ...:         super().start()
   ...:

In [4]: test = C()

In [5]: test.a
Out[5]: []

In [6]: test.start()

In [7]: test.a
Out[7]: ['bar', 'foo', 'something']

Copy link
Contributor

@g-braeunlich g-braeunlich Jun 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still to make my concerns clear: What I fear is the following:

test = C()
test.start()
...
test.start()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, that would create copies.
But it's getting called once, assuming the custom spawner is set using

c.JupyterHub.spawner_class = CustomSpawner

@g-braeunlich
Copy link
Contributor

Thx a lot. This is really fast!

@MridulS
Copy link
Contributor Author

MridulS commented Jun 2, 2021

I'll merge this and let me know if you are able to make it work with the subclass, if something isn't working we can fix it.

@g-braeunlich
Copy link
Contributor

OK. Thanks a lot!

@MridulS MridulS merged commit 9a2f906 into master Jun 2, 2021
@MridulS MridulS deleted the append_init branch June 2, 2021 15:12
@g-braeunlich
Copy link
Contributor

Fyi: In the end, I had to go a different path. Actually, I really want to launch my init container after the pbh container.
Therefore, I let inspire myself by your above MRO example and did:

class GitConfigurator(PersistentBinderSpawner.__base__):
    # private attributes
    _name: Optional[str] = None
    _email: Optional[str] = None

    def auth_state_hook(self, _spawner, auth_state):
        gitlab_user = auth_state.get("gitlab_user", {})
        self._name = gitlab_user.get("name")
        self._email = gitlab_user.get("email")

    def start(self):
        """This configures the git globals user.name, user.email"""
        git_commands = [
            f"git config --global --get {key} || git config --global {key} '{val}'"
            for (key, val) in (("user.name", self._name), ("user.email", self._email))
            if val is not None
        ]
        if git_commands:
            self.init_containers.append(
                {
                    "name": "rrp-git-configurator",
                    "image": "jupyter/minimal-notebook",
                    "command": [
                        "/bin/sh",
                        "-c",
                        " && ".join(git_commands),
                    ],
                    "volume_mounts": self.volume_mounts,
                }
            )
        return super().start()

And then used this in my actual spawner class like this:

class CustomPersistentBinderSpawner(PersistentBinderSpawner, GitConfigurator):
    ...

In this case, the chain of start would be:

  1. CustomPersistentBinderSpawner.start()
  2. PersistentBinderSpawner.start()
  3. GitConfigurator.start()
  4. KubeSpawner.start()
  5. start() of all bases of KubeSpawner

A bit hacky, but it works!

@MridulS MridulS restored the append_init branch June 11, 2021 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Preserve custom init_containers
2 participants