使用 Jenkins REST API 将 Jenkins 节点暂时标记为离线

Mark Jenkins node temporarily as offline by using the Jenkins REST API

我们有一个 Jenkins 矩阵作业,它在许多从属节点上并行测试我们软件的几个变体。有时会发生,其中一个从站崩溃并且必须重新启动。在这种情况下,我不想跳过 运行。我不想将特定的从节点标记为底层脚本暂时不可用,该脚本会检测到崩溃并随后重新启动节点。我发现,这应该可以通过 Jenkins REST API 实现。我找到了两个 python 库,它们应该可以完成这项工作; https://python-jenkins.readthedocs.org/en/latest/index.html and http://pythonhosted.org/jenkinsapi/index.html。但是这两个库在使用 python 3.4.3.

更改我的 Jenkins 1.580.2 系统(获取信息不是问题)时都存在问题

詹金斯API:

from jenkinsapi.jenkins import Jenkins
from jenkinsapi.utils.requester import Requester

class SSLRequester(Requester):
    def __init__(self, username=None, password=None):
        super(SSLRequester, self).__init__(username, password)

   def get_request_dict(self, *largs, **kwargs):
        requestKWargs = super(SSLRequester, self).get_request_dict(*largs, **kwargs)
        requestKWargs['verify'] = False
        return requestKWargs 

jenkins = Jenkins(jenkinsurl, username, password, requester=SSLRequester())

我必须使用自定义的 SSLRequester,因为我为我的 Jenkins 服务器使用 https:// 连接,否则我会收到以下错误

SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:600)

好吧,如果我尝试使用 jenkins 对象获取一些信息,一切都很好。

node.is_temporarily_offline()
False

但是如果我尝试切换节点,我会收到以下信息:

node.toggle_temporarily_offline()

JenkinsAPIException: Operation failed. url=https:///computer//toggleOffline?offlineMessage=requested%20from%20jenkinsapi, data={}, headers={'Content-Type': 'application/x-www-form-urlencoded'}, status=403, text=b"%2FtoggleOffline%3FofflineMessage%3Drequested%2520from%2520jenkinsapi'/>window.location.replace('/login?from=%2Fcomputer%2F%2FtoggleOffline%3FofflineMessage%3Drequested%2520from%2520jenkinsapi');\n\n\nAuthentication required\n\n\n

我的登录数据完全被忽略了。

python-詹金斯:

import jenkins
j = jenkins.Jenkins(jenkinsurl, username, password)
j.disable_node(slavenode)

TypeError: the JSON object must be str, not 'bytes'

经过短暂的 google 搜索,我发现我必须修补库,因为 JSON 不喜欢 Jenkins JSON 提供的字节数组API。插入几个 decode('utf-8') 语句后,我能够调用以下语句:

j.get_node_info(slavenode)

但我仍然无法将其标记为离线:

j.disable_node(slavenode)

TypeError: POST data should be bytes or an iterable of bytes. It cannot be of type str.

所以,把它归结为一个简单的问题。您是否知道其他一些方便的、可编写脚本的方法来将节点标记为暂时离线(当然,如果重启成功,则再次在线)?我更喜欢 python 解决方案,因为我从 python 脚本触发重启。但是 groovy 脚本也足够了。

在此先感谢您的帮助

你可以看看 script console where you can test scripts. You can also call these scripts using curl or the CLI,我想象一个 python 图书馆

这是一个很好的 groovy 脚本查看 nodes 并删除节点的例子

for (aSlave in hudson.model.Hudson.instance.slaves) {
  println('====================');
  println('Name: ' + aSlave.name);
  println('getLabelString: ' + aSlave.getLabelString());
  println('getNumExectutors: ' + aSlave.getNumExecutors());
  println('getRemoteFS: ' + aSlave.getRemoteFS());
  println('getMode: ' + aSlave.getMode());
  println('getRootPath: ' + aSlave.getRootPath());
  println('getDescriptor: ' + aSlave.getDescriptor());
  println('getComputer: ' + aSlave.getComputer());
  println('\tcomputer.isAcceptingTasks: ' + aSlave.getComputer().isAcceptingTasks());
  println('\tcomputer.isLaunchSupported: ' + aSlave.getComputer().isLaunchSupported());
  println('\tcomputer.getConnectTime: ' + aSlave.getComputer().getConnectTime());
  println('\tcomputer.getDemandStartMilliseconds: ' + aSlave.getComputer().getDemandStartMilliseconds());
  println('\tcomputer.isOffline: ' + aSlave.getComputer().isOffline());
  println('\tcomputer.countBusy: ' + aSlave.getComputer().countBusy());
  //if (aSlave.name == 'NAME OF NODE TO DELETE') {
  //  println('Shutting down node!!!!');
  //  aSlave.getComputer().setTemporarilyOffline(true,null);
  //  aSlave.getComputer().doDoDelete();
  //}
  println('\tcomputer.getLog: ' + aSlave.getComputer().getLog());
  println('\tcomputer.getBuilds: ' + aSlave.getComputer().getBuilds());
}