Skip to content

Conversation

cdleonard
Copy link

This adds a new class for managing lockable resources from python. It includes some helpful context managers so you can do stuff like this:

    with jenkins.lockable_resources.reservation_by_label("aaa") as r:
        print(f"locked resource {r.locked_resource_name}")

The intended use case is hardware reservation systems backed by jenkins. There is no CLI.

I also found a similar implementation as external package: https://gitlab.com/alexandre-perrin1/jenkins-lockable-resources. It seems unmaintained, I was unable to install due to dependency conflicts and such.

This PR contains full systest support so the CI will test the code against a running jenkins instance. Hopefully this makes it easy to maintain.

@cdleonard cdleonard force-pushed the lockable-resources branch 4 times, most recently from a9c0059 to 4a16129 Compare July 24, 2025 12:23
@cdleonard
Copy link
Author

This went through several force-pushes as I added more features and fix linting issues.

Current version is stable

@@ -779,3 +781,11 @@ def http_error_302(self, req, fp, code, msg, headers):
opener = build_opener(SmartRedirectHandler())
res = opener.open(request)
Requester.AUTH_COOKIE = res.cookie

_lockable_resources: Optional[LockableResources] = None
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you help me understand usage here?
Instead of just using a normal property method

Copy link
Author

Choose a reason for hiding this comment

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

It is meant to prevent creating multiple instance of the LockableResources class for each Jenkins instance - because why would you want that? But looking at how other entities are handled it is seems that only for Jobs a single instance is held inside Jenkins.jobs_container.

For consistency it makes sense to switch to a get_lockable_resources() method.

Copy link
Author

@cdleonard cdleonard Aug 25, 2025

Choose a reason for hiding this comment

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

Switched to a get_lockable_resources() method

return f"Lockable Resources @ {self.baseurl}"

def get_jenkins_obj(self) -> "Jenkins":
return self.jenkins
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not use just obj.jenkins?

Copy link
Author

@cdleonard cdleonard Aug 25, 2025

Choose a reason for hiding this comment

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

Most other JenkinsBase subclasses do this. The base JenkinsBase.get_jenkins_obj raises NotImplementedError so implementing this seems to be required.

Make JenkinsBase should just have a jenkins: Jenkins member? But that would be an unrelated refactor.


@property
def _requester(self) -> Requester:
return self.jenkins.requester
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't think we need this

Copy link
Author

Choose a reason for hiding this comment

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

removed


def poll(self, tree=None) -> None:
super().poll(tree)
self._data_dict = None
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why set this to none?

Copy link
Author

@cdleonard cdleonard Aug 25, 2025

Choose a reason for hiding this comment

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

It's cache invalidation.

The super().poll() call will update self._data and self._data_dict is generated based on self._data upon request (inside the data_dict getter method).

@cdleonard
Copy link
Author

Rebased addressing review comments and integrating a some other changes:

  • Rewrite RetryConfig so that it is reusable.
  • Turn ResourceSelector into ABC
  • Add custom ResourceReservationTimeoutError class
  • Add LockedResourceReservation.is_active, with tests
  • Remove unused LockedResourceReservation.locked field
  • Improve documentation

The RetryConfig class is very basic, the purpose of this abstraction is to allow more complex implementations - for example based on tenacity. I wanted to avoid adding dependencies.

@cdleonard
Copy link
Author

rebased to fix codacy

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.

2 participants