File: nodes.py

package info (click to toggle)
python-jenkinsapi 0.3.14-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 420 kB
  • sloc: python: 4,241; makefile: 3
file content (195 lines) | stat: -rw-r--r-- 6,239 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
"""
Module for jenkinsapi nodes
"""

from __future__ import annotations

from typing import Iterator

import logging

from urllib.parse import urlencode
from jenkinsapi.node import Node
from jenkinsapi.jenkinsbase import JenkinsBase
from jenkinsapi.custom_exceptions import JenkinsAPIException
from jenkinsapi.custom_exceptions import UnknownNode
from jenkinsapi.custom_exceptions import PostRequired

log: logging.Logger = logging.getLogger(__name__)


class Nodes(JenkinsBase):
    """
    Class to hold information on a collection of nodes
    """

    def __init__(self, baseurl: str, jenkins_obj: "Jenkins") -> None:
        """
        Handy access to all of the nodes on your Jenkins server
        """
        self.jenkins = jenkins_obj
        JenkinsBase.__init__(
            self,
            (
                baseurl.rstrip("/")
                if "/computer" in baseurl
                else baseurl.rstrip("/") + "/computer"
            ),
        )

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

    def __str__(self) -> str:
        return "Nodes @ %s" % self.baseurl

    def __contains__(self, node_name: str) -> bool:
        return node_name in self.keys()

    def iterkeys(self) -> Iterator[str]:
        """
        Return an iterator over the container's node names.

        Using iterkeys() while creating nodes may raise a RuntimeError
        or fail to iterate over all entries.
        """
        for item in self._data["computer"]:
            yield item["displayName"]

    def keys(self) -> list[str]:
        """
        Return a copy of the container's list of node names.
        """
        return list(self.iterkeys())

    def _make_node(self, nodename) -> Node:
        """
        Creates an instance of Node for the given nodename.
        This function assumes the returned node exists.
        """
        if nodename.lower() == "built-in node":
            nodeurl = "%s/(%s)" % (self.baseurl, "built-in")
        else:
            nodeurl = "%s/%s" % (self.baseurl, nodename)
        return Node(self.jenkins, nodeurl, nodename, node_dict={})

    def iteritems(self) -> Iterator[tuple[str, Node]]:
        """
        Return an iterator over the container's (name, node) pairs.

        Using iteritems() while creating nodes may raise a RuntimeError or
        fail to iterate over all entries.
        """
        for item in self._data["computer"]:
            nodename = item["displayName"]
            try:
                yield nodename, self._make_node(nodename)
            except Exception:
                raise JenkinsAPIException("Unable to iterate nodes")

    def items(self) -> list[tuple[str, Node]]:
        """
        Return a copy of the container's list of (name, node) pairs.
        """
        return list(self.iteritems())

    def itervalues(self) -> Iterator[Node]:
        """
        Return an iterator over the container's nodes.

        Using itervalues() while creating nodes may raise a RuntimeError
        or fail to iterate over all entries.
        """
        for item in self._data["computer"]:
            try:
                yield self._make_node(item["displayName"])
            except Exception:
                raise JenkinsAPIException("Unable to iterate nodes")

    def values(self) -> list[Node]:
        """
        Return a copy of the container's list of nodes.
        """
        return list(self.itervalues())

    def __getitem__(self, nodename: str) -> Node:
        if nodename in self:
            return self._make_node(nodename)
        raise UnknownNode(nodename)

    def __len__(self) -> int:
        return len(self.keys())

    def __delitem__(self, item: str) -> None:
        if item in self and item != "Built-In Node":
            url = "%s/doDelete" % self[item].baseurl
            try:
                self.jenkins.requester.get_and_confirm_status(url)
            except PostRequired:
                # Latest Jenkins requires POST here. GET kept for compatibility
                self.jenkins.requester.post_and_confirm_status(url, data={})
            self.poll()
        else:
            if item != "Built-In Node":
                raise UnknownNode("Node %s does not exist" % item)

            log.info("Requests to remove built-in node ignored")

    def __setitem__(self, name: str, node_dict: dict):
        if not isinstance(node_dict, dict):
            raise ValueError('"node_dict" parameter must be a Node dict')
        if name not in self:
            self.create_node(name, node_dict)
        self.poll()

    def create_node(self, name: str, node_dict: dict) -> Node:
        """
        Create a new slave node

        :param str name: name of slave
        :param dict node_dict: node dict (See Node class)
        :return: node obj
        """
        if name in self:
            return self[name]

        node = Node(
            jenkins_obj=self.jenkins,
            baseurl="",
            nodename=name,
            node_dict=node_dict,
            poll=False,
        )

        url = "%s/computer/doCreateItem?%s" % (
            self.jenkins.baseurl,
            urlencode(node.get_node_attributes()),
        )
        data = {"json": urlencode(node.get_node_attributes())}
        self.jenkins.requester.post_and_confirm_status(url, data=data)
        self.poll()
        return self[name]

    def create_node_with_config(self, name: str, config: dict) -> Node | None:
        """
        Create a new slave node with specific configuration.
        Config should be resemble the output of node.get_node_attributes()
        :param str name: name of slave
        :param dict config: Node attributes for Jenkins API request
            to create node
            (See function output Node.get_node_attributes())
        :return: node obj
        """
        if name in self:
            return self[name]

        if not isinstance(config, dict):
            return None
        url = "%s/computer/doCreateItem?%s" % (
            self.jenkins.baseurl,
            urlencode(config),
        )
        data = {"json": urlencode(config)}
        self.jenkins.requester.post_and_confirm_status(url, data=data)
        self.poll()
        return self[name]