63c2d1718eed43890ab5284510a6d8c975aec476
[lttng-ci.git] / automation / ansible / scripts / update_jenkins_node.py
1 #!/usr/bin/python3
2
3 import argparse
4 import configparser
5 import json
6 import sys
7 import xml.etree.ElementTree
8
9 import jenkins
10
11
12 def get_argument_parser():
13 parser = argparse.ArgumentParser(
14 prog="update_jenkins_node.py",
15 description="Create, update, or delete Jenkins nodes",
16 )
17 parser.add_argument(
18 "-u", "--url", default=None, help="Jenkins server URL including protocol"
19 )
20 parser.add_argument("--user", default=None, help="Jenkins username")
21 parser.add_argument("--password", default=None, help="Jenkins password")
22 parser.add_argument(
23 "-n",
24 "--node",
25 default=None,
26 required=True,
27 help="The name of the node to manage in Jenkins",
28 )
29 parser.add_argument(
30 "-c",
31 "--node-config",
32 default=[],
33 action="append",
34 help="An equals-separated set path=value[=attrib]. When attrib is not set, text is assumed",
35 )
36 parser.add_argument(
37 "-f",
38 "--config-file",
39 default=None,
40 type=argparse.FileType("r"),
41 help="An INI config file as used by jenkins_jobs",
42 )
43 parser.add_argument(
44 "-s",
45 "--state",
46 default="online",
47 choices=["online", "offline", "absent"],
48 help="The state of the Jenkins node",
49 )
50 parser.add_argument(
51 "-m",
52 "--message",
53 default="",
54 help="A message to set for the offline reason of a node",
55 )
56 parser.add_argument(
57 "-j",
58 "--json",
59 default="",
60 help="Additional config in a json dictionary which will be appended after -c items",
61 )
62 return parser
63
64
65 def manage_node(url, user, password, node, state, offline_message="", config={}):
66 server = jenkins.Jenkins(url, username=user, password=password)
67 exists = server.node_exists(node)
68 node_info = {}
69 changed = False
70 if exists and state == "absent":
71 server.delete_node(node)
72 changed = True
73 if not exists and state != "absent":
74 server.create_node(
75 node,
76 numExecutors=1,
77 remoteFS="/home/jenkins",
78 launcher=jenkins.LAUNCHER_SSH,
79 )
80 changed = True
81 if state != "absent":
82 # Check configuration
83 updated = False
84 node_config = xml.etree.ElementTree.fromstring(server.get_node_config(node))
85 for key, value in config.items():
86 element = node_config.find(key)
87 new_element = None
88 current_key = key
89 while element is None:
90 head = key.rsplit("/", 1)[0] if "/" in current_key else None
91 tail = key.rsplit("/", 1)[1] if "/" in current_key else current_key
92 e = xml.etree.ElementTree.Element(tail)
93 if new_element is not None:
94 e.append(new_element)
95 new_element = None
96 if head is None:
97 node_config.append(e)
98 element = node_config.find(key)
99 else:
100 parent = node_config.find(head)
101 if parent:
102 parent.append(e)
103 element = node_config.find(key)
104 else:
105 new_element = e
106 current_key = head
107 continue
108
109 if value["attrib"] is None:
110 if element.text != value["value"]:
111 updated = True
112 element.text = value["value"]
113 else:
114 try:
115 if element.attrib[value["attrib"]] != value["value"]:
116 updated = True
117 element.attrib[value["attrib"]] = value["value"]
118 except KeyError:
119 element.attrib[value["attrib"]] = value["value"]
120 updated = True
121 if updated:
122 xml_string = xml.etree.ElementTree.tostring(
123 node_config, xml_declaration=True, encoding="unicode"
124 )
125 server.reconfig_node(node, xml_string)
126 changed = True
127 # Online/offline
128 node_info = server.get_node_info(node)
129 if node_info["offline"] and state == "online":
130 server.enable_node(node)
131 changed = True
132 if not node_info["offline"] and state == "offline":
133 server.disable_node(node, offline_message)
134 changed = True
135 return changed
136
137
138 if __name__ == "__main__":
139 parser = get_argument_parser()
140 args = parser.parse_args()
141 if args.config_file is not None:
142 config = configparser.ConfigParser()
143 config.read_file(args.config_file)
144 if "jenkins" not in config.sections():
145 print("[jenkins] section not found")
146 sys.exit(1)
147 if args.url is None:
148 args.url = config.get("jenkins", "url")
149 if args.user is None:
150 args.user = config["jenkins"]["user"]
151 if args.password is None:
152 args.password = config["jenkins"]["password"]
153 assert args.user is not None
154 assert args.url is not None
155 assert args.password is not None
156 node_config = {}
157 for entry in args.node_config:
158 key, value = entry.split("=", 1)
159 node_config[key] = {
160 "attrib": value.split("=", 1)[1] if "=" in value else None,
161 "value": value.split("=", 1)[0] if "=" in value else value,
162 }
163 if args.json:
164 for key, value in json.loads(args.json).items():
165 node_config[key] = {
166 "attrib": value.split("=", 1)[1] if "=" in value else None,
167 "value": value.split("=", 1)[0] if "=" in value else value,
168 }
169 manage_node(
170 args.url,
171 args.user,
172 args.password,
173 args.node,
174 args.state,
175 args.message,
176 node_config,
177 )
This page took 0.035051 seconds and 5 git commands to generate.