Bootstrap

【Jenkins插件开发7】自定义任务功能——终止僵尸任务


Tips: 先说个感想,要开发Jenkins插件,真的要多看其他插件的源码。

添加功能菜单到每个任务

先看效果,如下图。一个普通的任务,我们想在侧边栏加上自己的功能。
在这里插入图片描述
官方给的Demo里,讲的是如何在build,也就是每次构建的侧边栏加功能菜单。其实差不多,先需要一个Action。build里加action是在perform方法中addAction,而我们需要继承一个扩展点类,在其createFor方法中返回action,具体如下:

  1. 添加扩展点,注意不要漏掉注解@Extension
@Extension
public class PaasTransientProjectActionFactory extends TransientProjectActionFactory {
    @Override
    public Collection<? extends Action> createFor(AbstractProject target) {
        return Collections.singleton(new StopAction(target));
    }
}
  1. Action类没啥特别的,多的doLog方法我们后边讲。
public class StopAction implements Action {

    private AbstractProject target;

    public StopAction(AbstractProject target) {
        this.target = target;
    }

    public void doLog(StaplerRequest req, StaplerResponse rsp) throws IOException {
        boolean flag = false;
        String name = req.getParameter("jobName");
        for (Thread thread : Thread.getAllStackTraces().keySet()) {
            if (thread.getName().contains(name)) {
                thread.stop();
                rsp.getWriter().write("1");
                flag = true;
                break;
            }
        }
        if (!flag) {
            rsp.getWriter().write("0");
        }
    }

    public AbstractProject getTarget() {
        return target;
    }

    @Override
    public String getIconFileName() {
        return "document.png";
    }

    @Override
    public String getDisplayName() {
        return "僵尸任务终止器";
    }

    @Override
    public String getUrlName() {
        return "zombie";
    }
}

前后台通信

之前我分享过一篇【Jenkins插件开发4】自定义后台接口,这次又有不一样的后台接口方式。
Jenkins使用一种叫Stapler的方式,将对象与url绑定起来,大家感兴趣可以自行搜索学习,我这里只说实现。
jelly页面如下,功能很简单,页面上有个按钮,点击就请求后台接口执行:

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:st="jelly:stapler">
    <l:layout title="Greeting">
        <l:side-panel>
            <st:include page="sidepanel.jelly" it="${it.target}" optional="true" />
        </l:side-panel>
        <l:main-panel>
            <b>此方法存在不安全可能,非必要不使用。正常停止任务请在build后点击停止按钮。</b>
            <button onclick="stop()">立即终止${it.target.fullName}</button>
        </l:main-panel>
    </l:layout>

    <script>
        function stop() {
            new Ajax.Request(location.href + "/log", {
                parameters:"jobName=${it.target.fullName}",
                onComplete:function(rs) {
                    alert(rs.responseText==1?'已终止,请稍后':'未成功');
                }
            });
        }
    </script>
</j:jelly>

这里后台接口的地址是:job任务地址 + action类urlName + action类方法名
大家意会一下吧,以我为例
Jenkins地址是:http://localhost:8080/jenkins
Job地址是:http://localhost:8080/jenkins/job/123
Job功能菜单地址是:http://localhost:8080/jenkins/job/123/zombie
Job功能后台地址是:http://localhost:8080/jenkins/job/123/zombie/log,对应Action里的doLog方法

啥是僵尸任务

这是我遇到的一个问题,任务都执行完了,但build还是运行状态,并且点stop也终止不了。最后我终于找到了一个不太优雅的解决办法(ps:当然,重启是可以解决的。)那就是执行以下脚本:

String name = "你的任务全名"
Thread.getAllStackTraces().keySet().each() {
  t -> if (t.getName().contains(name)) {   t.stop();  }
}

在下图的地方执行:
在这里插入图片描述
不过,我们公司大规模使用,权限分离,这个全局的脚本执行页面是不开放给每个组的,我只好将他开发成上面的功能了。

;