九月 25 2017

jenkins通过程序创建子节点

Jenkins CLI

Jenkins有一个内置的命令行,允许通过程序或shell请求Jenkins。即Jenkins CLI 

Jenkins CLI 包含:create-node,update-node,create-job,copy-job,offline-node等命令

jenkins-cli.jar包可以通过自己部署的jenkins,http:jenkins.example.com/cli 来下载。

Command create-node

创建节点命令介绍

java -jar jenkins-cli.jar -s http://10.1.0.243:8080/jenkins/ create-node [NODE]
Creates a new node by reading stdin as a XML configuration.
NODE : Name of the node

通过上面命令了解到,该命令需要从输入流获取xml配置文件。而节点的xml文件结构可以参考手工创建节点后在.jenkins下面
/home/user/.jenkins/nodes/xxx/config.xml生成的文件

通过shell来创建节点

创建jenkins-create-node.sh文件,如下

NS_URL='http://10.1.0.243:8180/jenkins'
NODE_NAME=$2
NODE_SLAVE_HOME=$1
EXECUTORS=1
SSH_PORT=22
CRED_ID=$3
HOST_NAME=$4
JAVA_OPT=$5
JAVA_PATH=$6

cat <<EOF | java -jar ./jenkins-cli.jar -s ${NS_URL} create-node $2
<slave>
  <name>${NODE_NAME}</name>
  <description></description>
  <remoteFS>$1</remoteFS>
  <numExecutors>${EXECUTORS}</numExecutors>
  <mode>NORMAL</mode>
  <retentionStrategy class="hudson.slaves.RetentionStrategy$Always"/>
  <launcher class="hudson.plugins.sshslaves.SSHLauncher" plugin="ssh-slaves@1.9">
    <host>$4</host>
    <port>${SSH_PORT}</port>
    <credentialsId>${CRED_ID}</credentialsId>
    <jvmOptions>${JAVA_OPT}</jvmOptions>
    <javaPath>${JAVA_PATH}</javaPath>
  </launcher>
  <label></label>
  <nodeProperties/>
  <userId>anonymous</userId>
</slave>
EOF

然后通过sh jenkins-create-node.sh  /home/bossbuild/remote-jenkins_243test  testll  89060efd-e391-4586-bfe7-95d6b74cfb65 10.1.4.82 -Dfile.encoding=gbk /home/bossbuild/jdk1.7.0_45/bin/java 来执行命令

89060efd-e391-4586-bfe7-95d6b74cfb65是jenkins为用户加密后生成的

通过java程序来创建节点

通过process.getOutputStream()来写入xml,因为Process在程序员的角度是OuputStream,对于程序的角度就是STDIN

Process process = Runtime.getRuntime().exec("java -jar ./jenkins-cli.jar -s http://10.1.0.243:8180/jenkins create-node  aaa");
OutputStream stdin = process.getOutputStream();
InputStream stdout = process.getInputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
writer.write("<slave><name>jobname</name><description></description><remoteFS>/home/bossbuild/remote-jenkins_243test</remoteFS><numExecutors>1</numExecutors><mode>NORMAL</mode><retentionStrategy class='hudson.slaves.RetentionStrategy$Always'/><launcher class='hudson.plugins.sshslaves.SSHLauncher' plugin='ssh-slaves@1.9'><host>10.1.4.82</host><port>22</port><credentialsId>89060efd-e391-4586-bfe7-95d6b74cfb65</credentialsId><jvmOptions>-Dfile.encoding=gbk</jvmOptions><javaPath>/home/bossbuild/jdk1.7.0_45/bin/java</javaPath></launcher><label></label><nodeProperties/><userId>anonymous</userId></slave>");
writer.flush();
writer.close();

一月 04 2017

cas 配置https改为ip而不是使用域名

cas注销时地址是https,提示Error is [java.security.cert.CertificateException: No subject alternative names present]

因为某些原因,访问cas以及子系统希望通过ip来访问并且要使用https协议

网上很多文章说要使用CAS单点登录必须要配置域名, cas server是不能通过ip访问的,这实际上是错误的,这和cas无关,目前可以通过java 1.7来生成证书,需要JDK1.7,因为需要-ext参数 

生成证书方式

keytool -genkey -alias cas41key -keyalg RSA -keysize 1024 -keypass 123456 -storepass 123456  -dname "CN=10.1.4.41,OU=csoa,O=csoa,L=FZ,ST=FZ,C=CN" -ext san=ip:10.1.4.41   -validity 3600  -keystore /home/nloa/bak/cas41.keystore

RFC 2818 (Section 3.1)

If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead.

[...]

In some cases, the URI is specified as an IP address rather than a hostname. In this case, the iPAddress subjectAltName must be present in the certificate and must exactly match the IP in the URI.

jdk1.7,查阅keytool参数文档,keytool可以使用-ext san=dns:www.example.com 或者 -ext san=ip:10.0.0.1 来包括Subject Alternative Name (SAN,主题备用名称)

具体配置文档 CAS文档.docx

六月 26 2016

jenkins执行shell读不到环境变量问题

jenkins远程执行shell源码分析系列中,了解到jenkins执行shell的原理。在使用jenkins过程中,发现执行shell读取不到/etc/profile以及用户下.bash_profile设置的环境变量。

环境:Red Hat Enterprise 5.5

根据jenkins-core项目Shell.java的buildCommandLine方法

   public String[] buildCommandLine(FilePath script) {
       if(command.startsWith("#!")) {
           // interpreter override
           int end = command.indexOf('\n');
           if(end<0)   end=command.length();
            List<String> args = new ArrayList<String>();
            args.addAll(Arrays.asList(Util.tokenize(command.substring(0,end).trim())));
            args.add(script.getRemote());
            args.set(0,args.get(0).substring(2));   // trim off "#!"
           return args.toArray(new String[args.size()]);
       } else
           return new String[] { getDescriptor().getShellOrDefault(script.getChannel()), "-xe", script.getRemote()};
   }

在默认的情况下,执行shell会在节点上tmp目录生成类似hudson224519953209659762.sh(后面数字根据规则生成),具体执行的命令如:
/bin/sh -xe /tmp/hudson224519953209659762.sh。

如果Execute Shell里面具体命令为以下内容:

#!/bin/bash +x
...
...

那么根据上面代码,具体执行的命令就会变成/bin/bash +x /tmp/hudson224519953209659762.sh

知道jenkins执行shell的原理后,接下来我们要谈谈交互式和非交互式shell、登录和非登录shell之间的区别

什么是交互式shell(interactive shell)和非交互式shell(non-interactive shell)

交互式的shell会有一个输入提示符,并且它的标准输入、输出和错误输出都会显示在控制台上。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、退出。当你退出后,shell也终止了。

非交互式shell是bash script.sh这类的shell。在这种模式下,shell不与你进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾EOF,shell也就终止了。

什么是登录式shell(login shell)和非登陆式shell(no-login shell)

需要输入用户名和密码的shell就是登陆式shell。因此通常不管以何种方式登陆机器后用户获得的第一个shell就是login shell。不输入密码的ssh是公钥打通的,某种意义上说也是输入密码的。

非登陆式的就是在登陆后启动bash等,即不是远程登陆到主机这种。

通过man bash了解login shell和interactive shell,如下

INVOCATION
       A login shell is one whose first character of argument zero is a -, or one started with the --login option.

       An interactive shell is one started without non-option arguments and without the -c option whose standard input
       and error are both connected to terminals (as determined by isatty(3)), or one started with the -i option.  PS1
       is set and $- includes i if bash is interactive, allowing a shell script or a startup file to test this  state.

       The following paragraphs describe how bash executes its startup files.  If any of the files exist but cannot be
       read, bash reports an error.  Tildes are expanded in file names as described below under Tilde Expansion in the
       EXPANSION section.

       When  bash  is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it
       first reads and executes commands from the file /etc/profile, if that file exists.  After reading that file, it
       looks  for  ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from
       the first one that exists and is readable.  The --noprofile option may be used when the  shell  is  started  to
       inhibit this behavior.

       When a login shell exits, bash reads and executes commands from the file ~/.bash_logout, if it exists.

       When  an  interactive  shell  that  is  not  a  login  shell  is started, bash reads and executes commands from
       ~/.bashrc, if that file exists.  This may be inhibited by using the --norc option.  The  --rcfile  file  option
       will force bash to read and execute commands from file instead of ~/.bashrc.

       When  bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV
       in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to
      read and execute.  Bash behaves as if the following command were executed:
             if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
       but the value of the PATH variable is not used to search for the file name.

对man bash解读:

如果一个bash是交互式登录Shell或者使用--login参数的非交互式Shell。首先会执行/etc/profile文件。然后按顺序查找~/.bash_profile, ~/.bash_login,~/.profile,这三个文件谁存在并且有读权限就执行谁,然后后面的就不会再执行。可以通过指定--noprofile参数来禁止这种默认行为。当登录Shell退出之后,bash会读取~/.bash_logout文件并执行。

如果 ~/.bash_profile文件存在的话,一般还会执行 ~/.bashrc文件。因为在~/.bash_profile文件中一般会有下面的代码:

if [ -f ~/.bashrc ]; then
  . ~/.bashrc
fi

~/.bashrc中,一般还会有以下代码:

if [ -f /etc/bashrc ]; then
  . /etc/bashrc
fi

所以执行顺序为:

 /etc/profile -> (~/.bash_profile | ~/.bash_login | ~/.profile) -> ~/.bashrc -> /etc/bashrc -> ~/.bash_logout

如果是一个交互式非登录Shell,bash会读取~/.bashrc文件。同时,可以指定--norc参数来禁止该行为,或者通过--rcfile指定其它文件。

如果是一个非交互式非登录Shell,比如运行一个Shell脚本,它会在环境查找BASH_ENV变量。

通过上面的分析,对于常用环境变量设置文件,整理出如下加载情况表:

文件非交互+登陆式交互+登陆式交互+非登陆式非交互+非登陆式
/etc/profile加载加载
/etc/bashrc加载加载
~/.bash_profile加载加载
~/.bashrc加载加载加载
BASH_ENV加载

执行脚本,如bash script.sh是属于non-login + non-interactive

所以jenkins默认情况下/bin/sh -xe /tmp/hudson224519953209659762.sh 是属于non-login + non-interactive

解决方案

通过man bash可知:

OPTIONS
       In  addition  to  the  single-character shell options documented in the description of the set builtin command,
       bash interprets the following options when it is invoked:

       -c string If the -c option is present, then commands are read from string.  If there are  arguments  after  the
                 string, they are assigned to the positional parameters, starting with $0.
       -i        If the -i option is present, the shell is interactive.
       -l        Make bash act as if it had been invoked as a login shell (see INVOCATION below).
       -r        If the -r option is present, the shell becomes restricted (see RESTRICTED SHELL below).
       -s        If  the  -s  option  is present, or if no arguments remain after option processing, then commands are
                read from the standard input.  This option allows the positional parameters to be set  when  invoking
                 an interactive shell.
       -D        A  list  of all double-quoted strings preceded by $ is printed on the standard output.  These are the
                 strings that are subject to language translation when the current locale is not  C  or  POSIX.   This
                 implies the -n option; no commands will be executed.

可以通过-i参数和-l参数让bash为login shell and interactive shell,就可以读取/etc/profile~/.bash_profile等文件。

即在jenkins Execute Shell里可以这么写

#!/bin/bash -ilex
...

...

对于e参数表示一旦出错,就退出当前的shell,x参数表示可以显示所执行的每一条命令

环境:HP-UX

HP-UX中使用的默认shell是POSIX shell,也就是/usr/bin/sh,并且提供了ksh和csh,但就是不提供bash,所以要使用bash需要自己安装。

通过man sh-posix了解到上述的解决方案是不能使用,因为sh-posix有-i参数,但是没有-l参数。

解决方案

所以在HP-UX环境下,在jenkins Execute Shell里可以这么写

#!/bin/sh +x
. /etc/profile

BPFile="$HOME/.bash_profile"
PFile="$HOME/.profile"
exeFile=""
if [ -f "$PFile" ]; then
exeFile=". $PFile"
elif [ -f "$BPFile" ]; then
exeFile=". $BPFile"
fi
$exeFile
set -e
...
...

通过shell执行/etc/profile和~/.profile来模拟login shell and interactive shell

标签:
在2005/01/28 15:50上被superadmin创建
 
本站采用XWiki系统搭建