Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 1 | import logging |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 2 | |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 3 | logger = logging.getLogger(__name__) |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 4 | |
| 5 | create_node_groovy = u"""\ |
| 6 | import jenkins.model.* |
| 7 | import hudson.model.* |
| 8 | import hudson.slaves.* |
| 9 | import hudson.plugins.sshslaves.* |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 10 | |
Dmitry Burmistrov | 2a3ba9c | 2018-03-15 19:22:32 +0400 | [diff] [blame] | 11 | def launcherName = ${launcher}.getClass().getName() |
| 12 | def retStrategyName = new hudson.slaves.RetentionStrategy.${ret_strategy}().getClass().getName() |
| 13 | |
| 14 | |
| 15 | switch (launcherName) { |
| 16 | case 'hudson.slaves.JNLPLauncher': |
| 17 | result = Jenkins.instance.slaves.find{ |
| 18 | it.name == "${name}" && |
| 19 | it.numExecutors == ${num_executors} && |
| 20 | it.nodeDescription == "${desc}" && |
| 21 | it.remoteFS == "${remote_home}" && |
| 22 | it.labelString == "${label}" && |
| 23 | it.mode == Node.Mode.${node_mode} && |
| 24 | it.launcher.tunnel == ("${tunnel}" ?: null) && |
| 25 | it.launcher.vmargs == ("${jvmopts}" ?: null) && |
| 26 | it.launcher.getClass().getName().equals(launcherName) && |
| 27 | it.retentionStrategy.getClass().getName().equals(retStrategyName) |
| 28 | } |
| 29 | break |
| 30 | default: |
| 31 | result = Jenkins.instance.slaves.find{ |
| 32 | it.name == "${name}" && |
| 33 | it.numExecutors == ${num_executors} && |
| 34 | it.nodeDescription == "${desc}" && |
| 35 | it.remoteFS == "${remote_home}" && |
| 36 | it.labelString == "${label}" && |
| 37 | it.mode == Node.Mode.${node_mode} && |
| 38 | it.launcher.jvmOptions == "${jvmopts}" && |
| 39 | it.launcher.getClass().getName().equals(launcherName) && |
| 40 | it.retentionStrategy.getClass().getName().equals(retStrategyName) |
| 41 | } |
| 42 | break |
| 43 | } |
| 44 | |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 45 | if(result){ |
Dmitry Burmistrov | 2a3ba9c | 2018-03-15 19:22:32 +0400 | [diff] [blame] | 46 | print("EXISTS") |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 47 | }else{ |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 48 | Slave slave = new DumbSlave( |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 49 | "${name}", |
| 50 | "${desc}", |
| 51 | "${remote_home}", |
| 52 | "${num_executors}", |
| 53 | Node.Mode.${node_mode}, |
| 54 | "${label}", |
| 55 | ${launcher}, |
| 56 | new RetentionStrategy.${ret_strategy}(), |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 57 | new LinkedList()) |
| 58 | Jenkins.instance.addNode(slave) |
Jakub Josef | 98123ab | 2016-12-14 14:05:01 +0100 | [diff] [blame] | 59 | print("CREATED") |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 60 | } |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 61 | """ # noqa |
| 62 | |
| 63 | create_lbl_groovy = u"""\ |
| 64 | hudson = hudson.model.Hudson.instance |
| 65 | updated = false |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 66 | hudson.slaves.find { slave -> slave.nodeName.equals("${name}") |
| 67 | if({append}){ |
| 68 | slave.labelString = slave.labelString + " " + "${lbl_text}" |
| 69 | }else{ |
| 70 | slave.labelString = "${lbl_text}" |
| 71 | } |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 72 | updated = true |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 73 | print "${lbl_text}" |
| 74 | } |
| 75 | if(!updated){ |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 76 | print "FAILED" |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 77 | } |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 78 | hudson.save() |
| 79 | """ # noqa |
| 80 | |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 81 | configure_master_groovy = u"""\ |
| 82 | def instance = Jenkins.instance |
| 83 | def changed = false |
| 84 | |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 85 | if(Jenkins.instance.numExecutors != ${num_executors}){ |
| 86 | Jenkins.instance.setNumExecutors(${num_executors}) |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 87 | changed = true |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 88 | } |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 89 | |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 90 | if(!Jenkins.instance.mode.name.equals(new String("${node_mode}").toUpperCase())){ |
| 91 | Jenkins.instance.setMode(Node.Mode.${node_mode}) |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 92 | changed = true |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 93 | } |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 94 | |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 95 | if(!Jenkins.instance.labelString.equals("${labels}")){ |
| 96 | Jenkins.instance.setLabelString("${labels}") |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 97 | changed = true |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 98 | } |
| 99 | if(changed){ |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 100 | Jenkins.instance.save() |
Jakub Josef | 7339a00 | 2017-06-09 11:33:02 +0200 | [diff] [blame] | 101 | print("CREATED") |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 102 | }else{ |
Jakub Josef | 5878754 | 2017-06-08 16:59:47 +0200 | [diff] [blame] | 103 | print("EXISTS") |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 104 | } |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 105 | """ |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 106 | |
Ilya Kharin | 3d8bffe | 2017-06-22 17:40:31 +0400 | [diff] [blame] | 107 | |
| 108 | def __virtual__(): |
| 109 | ''' |
| 110 | Only load if jenkins_common module exist. |
| 111 | ''' |
| 112 | if 'jenkins_common.call_groovy_script' not in __salt__: |
| 113 | return ( |
| 114 | False, |
| 115 | 'The jenkins_node state module cannot be loaded: ' |
| 116 | 'jenkins_common not found') |
| 117 | return True |
| 118 | |
| 119 | |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 120 | def label(name, lbl_text, append=False): |
| 121 | """ |
| 122 | Jenkins node label state method |
| 123 | |
| 124 | :param name: node name |
| 125 | :param lbl_text: label text |
| 126 | :returns: salt-specified state dict |
| 127 | """ |
| 128 | test = __opts__['test'] # noqa |
| 129 | ret = { |
| 130 | 'name': name, |
| 131 | 'changes': {}, |
| 132 | 'result': False, |
| 133 | 'comment': '', |
| 134 | } |
| 135 | result = False |
| 136 | if test: |
| 137 | status = 'CREATED' |
| 138 | ret['changes'][name] = status |
| 139 | ret['comment'] = 'Label %s %s' % (name, status.lower()) |
| 140 | else: |
| 141 | call_result = __salt__['jenkins_common.call_groovy_script']( |
| 142 | create_lbl_groovy, {'name': name, 'lbl_text': lbl_text, 'append': "true" if append else "false"}) |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 143 | if call_result["code"] == 200 and call_result["msg"].strip( |
| 144 | ) == lbl_text: |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 145 | status = "CREATED" |
| 146 | ret['changes'][name] = status |
| 147 | ret['comment'] = 'Label %s %s ' % (name, status.lower()) |
| 148 | result = True |
| 149 | else: |
| 150 | status = 'FAILED' |
| 151 | logger.error( |
| 152 | "Jenkins label API call failure: %s", call_result["msg"]) |
| 153 | ret['comment'] = 'Jenkins label API call failure: %s' % ( |
| 154 | call_result["msg"]) |
| 155 | ret['result'] = None if test else result |
| 156 | return ret |
| 157 | |
| 158 | |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 159 | def present(name, remote_home, launcher, num_executors="1", |
| 160 | node_mode="Normal", desc="", labels=[], ret_strategy="Always"): |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 161 | """ |
| 162 | Jenkins node state method |
| 163 | |
| 164 | :param name: node name |
| 165 | :param remote_home: node remote home path |
| 166 | :param launcher: launcher dict with type, name, port, username, password |
| 167 | :param num_executors: number of node executurs (optional, default 1) |
| 168 | :param node_mode: node mode (optional, default Normal) |
Jakub Josef | 98123ab | 2016-12-14 14:05:01 +0100 | [diff] [blame] | 169 | :param desc: node description (optional) |
| 170 | :param labels: node labels list (optional) |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 171 | :param ret_strategy: node retention strategy from RetentionStrategy class |
| 172 | :returns: salt-specified state dict |
| 173 | """ |
| 174 | test = __opts__['test'] # noqa |
| 175 | ret = { |
| 176 | 'name': name, |
| 177 | 'changes': {}, |
| 178 | 'result': False, |
| 179 | 'comment': '', |
| 180 | } |
| 181 | result = False |
| 182 | if test: |
| 183 | status = 'CREATED' |
| 184 | ret['changes'][name] = status |
| 185 | ret['comment'] = 'Node %s %s' % (name, status.lower()) |
| 186 | else: |
Jakub Josef | 98123ab | 2016-12-14 14:05:01 +0100 | [diff] [blame] | 187 | label_string = " ".join(labels) |
| 188 | launcher_string = "new hudson.slaves.JNLPLauncher()" |
Dmitry Burmistrov | 2a3ba9c | 2018-03-15 19:22:32 +0400 | [diff] [blame] | 189 | tunnel_string = "" |
| 190 | jvmopts_string = "" |
| 191 | if "jvmopts" in launcher: |
| 192 | jvmopts_string = launcher["jvmopts"] |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 193 | if launcher: |
| 194 | if launcher["type"] == "ssh": |
Dmitry Burmistrov | 2a3ba9c | 2018-03-15 19:22:32 +0400 | [diff] [blame] | 195 | launcher_string = 'new hudson.plugins.sshslaves.SSHLauncher("{}",{},"{}","{}","","{}","","","")'.format( |
| 196 | launcher["host"], launcher["port"], launcher["username"], |
| 197 | launcher["password"], jvmopts_string) |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 198 | elif launcher["type"] == "jnlp": |
Dmitry Burmistrov | 2a3ba9c | 2018-03-15 19:22:32 +0400 | [diff] [blame] | 199 | if "tunnel" in launcher: |
| 200 | tunnel_string = launcher["tunnel"] |
| 201 | launcher_string = 'new hudson.slaves.JNLPLauncher("{}","{}")'.format( |
| 202 | tunnel_string, jvmopts_string) |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 203 | |
| 204 | call_result = __salt__['jenkins_common.call_groovy_script']( |
| 205 | create_node_groovy, |
| 206 | {"name": name, |
Jakub Josef | 95ad980 | 2017-01-17 15:59:00 +0100 | [diff] [blame] | 207 | "desc": desc if desc else "", |
| 208 | "label": label_string if label_string else "", |
| 209 | "remote_home": remote_home if remote_home else "", |
| 210 | "num_executors": num_executors if num_executors else "1", |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 211 | "launcher": launcher_string, |
Dmitry Burmistrov | 2a3ba9c | 2018-03-15 19:22:32 +0400 | [diff] [blame] | 212 | "tunnel": tunnel_string, |
| 213 | "jvmopts": jvmopts_string, |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 214 | "node_mode": node_mode.upper(), |
Jakub Josef | 95ad980 | 2017-01-17 15:59:00 +0100 | [diff] [blame] | 215 | "ret_strategy": ret_strategy if ret_strategy else "Always"}) |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 216 | if call_result["code"] == 200 and call_result["msg"] in [ |
| 217 | "CREATED", "EXISTS"]: |
Jakub Josef | 98123ab | 2016-12-14 14:05:01 +0100 | [diff] [blame] | 218 | status = call_result["msg"] |
| 219 | if call_result["msg"] == "CREATED": |
| 220 | ret['changes'][name] = status |
Jakub Josef | 123be7a | 2016-12-12 16:02:36 +0100 | [diff] [blame] | 221 | ret['comment'] = 'Node %s %s' % (name, status.lower()) |
| 222 | result = True |
| 223 | else: |
| 224 | status = 'FAILED' |
| 225 | logger.error( |
| 226 | "Jenkins node API call failure: %s", call_result["msg"]) |
| 227 | ret['comment'] = 'Jenkins node API call failure: %s' % ( |
| 228 | call_result["msg"]) |
| 229 | ret['result'] = None if test else result |
| 230 | return ret |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 231 | |
Jakub Josef | d2a6203 | 2017-06-06 17:53:21 +0200 | [diff] [blame] | 232 | |
| 233 | def setup_master(name, num_executors="1", node_mode="Normal", labels=[]): |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 234 | """ |
| 235 | Jenkins setup master state method |
| 236 | |
| 237 | :param name: node name (master) |
| 238 | :param num_executors: number of executors (optional, default 1) |
| 239 | :param node_mode: Node mode (Normal or Exclusive) |
Jakub Josef | d2a6203 | 2017-06-06 17:53:21 +0200 | [diff] [blame] | 240 | :param labels: array of labels |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 241 | :returns: salt-specified state dict |
| 242 | """ |
| 243 | test = __opts__['test'] # noqa |
| 244 | ret = { |
| 245 | 'name': name, |
| 246 | 'changes': {}, |
| 247 | 'result': False, |
| 248 | 'comment': '', |
| 249 | } |
| 250 | result = False |
| 251 | if test: |
| 252 | status = 'CREATED' |
| 253 | ret['changes'][name] = status |
Jakub Josef | d2a6203 | 2017-06-06 17:53:21 +0200 | [diff] [blame] | 254 | ret['comment'] = 'Master node %s' % (status.lower()) |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 255 | else: |
| 256 | call_result = __salt__['jenkins_common.call_groovy_script']( |
Jakub Josef | 7339a00 | 2017-06-09 11:33:02 +0200 | [diff] [blame] | 257 | configure_master_groovy, {'num_executors': num_executors, 'labels': " ".join(labels), 'node_mode': node_mode.upper()}) |
Adam Tengler | 70763e0 | 2017-08-21 16:50:32 +0000 | [diff] [blame] | 258 | if call_result["code"] == 200 and call_result["msg"] in [ |
| 259 | "CREATED", "EXISTS"]: |
Jakub Josef | 5878754 | 2017-06-08 16:59:47 +0200 | [diff] [blame] | 260 | status = call_result["msg"] |
| 261 | if status == "CREATED": |
| 262 | ret['changes'][name] = status |
| 263 | ret['comment'] = 'Master node configuration %s ' % (status.lower()) |
Jakub Josef | 1bb7f44 | 2017-05-26 17:02:56 +0200 | [diff] [blame] | 264 | result = True |
| 265 | else: |
| 266 | status = 'FAILED' |
| 267 | logger.error( |
| 268 | "Jenkins master configure API call failure: %s", call_result["msg"]) |
| 269 | ret['comment'] = 'Jenkins master configure API call failure: %s' % ( |
| 270 | call_result["msg"]) |
| 271 | ret['result'] = None if test else result |
Jakub Josef | d2a6203 | 2017-06-06 17:53:21 +0200 | [diff] [blame] | 272 | return ret |