SSH Timeout problem with Jenkins and maven ant plugin

The problem:

Recently a Jenkins job would report a problem from a particular script:

Remote command failed with exit status -1.

This problem happened when using the command sshexec task from maven ant plugin:

<sshexec host="${host}" username="${login}" password="${pwd}" command="sh longcommand.sh" trust="true"

After long investigation I realised the problem was not coming from the script but from the distant server. Indeed the connection with the server would stop when a process was running more than 200 seconds.

The solution

    Ssh Configuration solution

At first I decided to modify directly the ssh configuration of the distant server.

http://z9.io/2008/12/10/how-to-fix-ssh-timeout-problems/

I modified directly in the file  /etc/ssh/sshd_config the value ClientAliveInterval from 200 to 2000. Then I restarted the server httpd : /etc/init.d/sshd restart . It fixes the issue but the solution was refused.
Therefore I decided to modify the ssh client configuration instead. But I did not find how to configure the sshexec task https://ant.apache.org/manual/Tasks/sshexec.html. I don’t have access to /etc/ssh/ssh_config in the client machine either.

Workaround for running long command remotely.

This solution works for me :https://groups.google.com/forum/#!msg/rundeck-discuss/iK55if9Vk9E/skNPHAfF3qgJ.

Instead of running:


sh longcommand.sh

I run:


truncate -s 0 /mydir/log.out
nohup longcommand.sh  > /mydir/log.out 2>&1 &
PID=`echo $!`
echo "$PID"
for (( ; ; ))
do
sleep 30
if ps -p $PID > /dev/null
then
echo "longcommand running"
else
echo "longcommand executed"
break
fi
done
cat /mydir/log.out

If you compare the original solution to mine i just deleted 0<&-.

Automate the installation of a product with bash scripts

The problem

I was given the repetitive task to make an archive and install the content on a machine every 3 weeks. This archive contained sql files and shell scripts. A shell script would install the product and create a database.

The procedure was entirely manual and repetitive. I decided steps by steps to automate all the procedure with maven and ant plugin. With Jenkins I launched the procedure daily ,thus I could detect problems early.
I have been using mavento create the archive. Then I used maven plugin “maven-antrun-plugin” to install automatically the archive on a distant server.

Generate the archive

Content of the pom.xml

First of all I had to generate an archive with maven-assembly plugin. This following plugin will call the file assembly.xml to generate an archive of type zip.


<plugin>
<inherited>false</inherited>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>

Content of the assembly.xml

This is the headline of the assembly. The variable ${name} is defined in the properties file of the  pom.

<assembly>
<id>${name}</id>
<formats>
<format>dir</format>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>

The filesets will add files from the local code in the archive. I can as well exclude all files of type txt for example if I don’t want them in the archive.

<fileSets>
        <fileSet>
            <directory>${basedir}/src/main/resources</directory>
            <outputDirectory>/</outputDirectory>
            <lineEnding>unix</lineEnding>
            <fileMode>755</fileMode>
            <directoryMode>755</directoryMode>
            <excludes>
                <exclude>**/*.txt</exclude>
            </excludes>
        </fileSet>
    </fileSets>

Below I select the module child1 in the tree of my modules. Then I retrieve the content of the directory src/main in the module child1. I include all text files of types war,properties, etc…

More information on moduleSets :

http://maven.apache.org/plugins/maven-assembly-plugin/advanced-module-set-topics.html

<moduleSets>
<moduleSet>
<includes>
<include>org.lib:child1</include>
</includes>
<sources>
<fileSets>
<fileSet>
<directory>src/main</directory>
<outputDirectory>/</outputDirectory>
<fileMode>755</fileMode>
<lineEnding>keep</lineEnding>
<directoryMode>755</directoryMode>
<includes>
<include>**/*.war</include>
<include>**/*.properties</include>
<include>**/*.jar</include>
<include>**/*.dump</include>
</includes>
</fileSet>
<moduleSet>
<moduleSets>

Then I want to retrieve some dependencies of the pom into my archive file :

<dependencySets>
<dependencySet>
<outputFileNameMapping>
myapp.war
</outputFileNameMapping>
<outputDirectory>/web</outputDirectory>
<includes>
<include>org.lib:web</include>
</includes>
</dependencySet>

That’s it : I have created a basic archive.

Install the archive in some distant server

Content of the pom.xml

In order to install the archive in some distant server I used the plugin maven-antrun-plugin

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <inherited>false</inherited>
                <dependencies>
                    <dependency>
                        <groupId>org.apache.ant</groupId>
                        <artifactId>ant-jsch</artifactId>
                        <version>1.7.0</version>
                    </dependency>
                    <dependency>
                        <groupId>com.jcraft</groupId>
                        <artifactId>jsch</artifactId>
                        <version>0.1.51</version>
                    </dependency>
                    <dependency>
                        <groupId>ant-contrib</groupId>
                        <artifactId>ant-contrib</artifactId>
                        <version>1.0b3</version>
                        <scope>compile</scope>
                        <exclusions>
                            <exclusion>
                                <groupId>ant</groupId>
                                <artifactId>ant</artifactId>
                             </exclusion>
                        </exclusions>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <id>install</id>
                        <phase>install</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <property name="compile_classpath" refid="maven.compile.classpath"/>
                                <property name="runtime_classpath" refid="maven.runtime.classpath"/>
                                <property name="test_classpath" refid="maven.test.classpath"/>
                                <property name="plugin_classpath" refid="maven.plugin.classpath"/>
                                <property name="remote_host" value="${remoteHost}"/>
                                                               <property name="remote.dir" value="${remote.dir}"/>
                                <property name="remote.login" value="${remote.login}"/>
                                <property name="remote.pwd" value="${remote.pwd}"/>
                                 
                                <ant antfile="${antdir}">
                                    <target name="deploy"/>
                                </ant>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <properties>
                <remote.login>login</remote.login>
                <remote.pwd>pass</remote.pwd>
                <remoteHost>blaha.org.2015.com</remoteHost>
                <remote.dir>/remote/dir</remote.dir>
                <antdir>src/main/resources/ant/build.xml</antdir>
            </properties></pre>
<pre>

The plugin maven will call the build.xml. All variables set in <tasks> are sent to the build.xml file.

build.xml:

The default target of the build.xml is in the  header.Here I have defined some properties and load some constants from the file build.properties.

<?xml version="1.0" encoding="UTF-8"?>
<project name="Build" basedir="." default="deploy">

<property name="baseDirectory" location="./target" />

<property name="myworkspace" location="${baseDirectory}" />
<property file="${baseDirectory}/build.properties" />

Here is defined the target deploy .If remote.dir is not defined I can take the value /remote/dir by default.

<target name="deploy">
      <if>
          <equals arg1="${remote.dir}" arg2="" />
          <then>
              <property name="remote_dir" value="/remote/dir" />
          </then>
          <else>
        <property name="remote_dir" value="${remote.dir}" />
          </else>
      </if>

Another ant file is called. It is useful when we want to factor some ant code.

<ant antfile="src/main/resources/ant/build_common.xml" target="deploy"/>

Copy the zip file(scp) generated from the current directory to the distant server remote_host at the remote_dir folder

 <scp todir="${remote_login}:${remote_pwd}@${remote_host}:${remote_dir}/" file="${baseDirectory}/${archive}.zip" trust="true" />

Execute a command unzip on the remote server  with sshexec.

    <sshexec host="${remote_host}" username="${remote_login}" password="${remote_pwd}" command="cd ${remote_dir};unzip -o ${remote_dir}/colis/${name.archive.full}.zip;" trust="true" />

Execution of bash script which will install the product, create the database, etc…

  <sshexec host="${remote_host}" username="${remote_login}" password="${remote_pwd}" command="cd ${remote_dir};${remote_dir}/install.sh" trust="true" />

After the installation I need to import a dump on the distant server. As you can see i defined the variables before calling the script.

  <sshexec host="${remote_host}" username="${remote_login}" password="${remote_pwd}" command="export ORACLE_HOME=${oracle_home};export ORACLE_SID=${oracle_sid};${oracle_home}/bin/imp login/pass file=/mydir/mydump.dump tables=* commit=y ignore=y" trust="true" />

Conclusion

From spending two to four days in manual installing every three weeks, I spend only half days now doing this process.

Furthermore I had also to manually install and test a patch at each delivery. This patch is now created and installed automatically. I have done it in the same pom so it was a bit tricky. Maybe i will explain in another post.

Unit Testing of Jsp Custom Tag Before Version Spring 2.5

As it is described on this link, it is easier to mock Custom Tag with Spring 2.5 :http://blog.agilelogicsolutions.com/2011/02/unit-testing-jsp-custom-tag-using.html .

If for whatever reason you are stuck with a version of Spring before 2.5, you can still test Jsp Custom Tag.This is the class i would like to unit test :


public final class CustomTag extends javax.servlet.jsp.tagext.BodyTagSupport{

    public void writeMyTag() throws JspException {

              pageContext.getOut().write("<th> … text here <th>");              

   }

}


My problem is : how to mock the object pageContext ? My solution is to use Mockito.

I did the following unit test and mock pageContext and jspWriter:


public class CustomTagTest {

@Mock

PageContext pageContext;

@Mock

JspWriter jspWriter;

@Before

public void setup(){

MockitoAnnotations.initMocks(this);

}

@Test

public void testwriteMyTag() throws JspException, IOException {

CustomTag tag = new CustomTag ();

(Mockito.doReturn(jspWriter).when(pageContext)).getOut();

tag.setPageContext(pageContext );

tag.writeMyTag();

}

}

Here we go : i covered the custom tag code. However it does not test the output result of JspWriter.

The power of Unit Testing

Why Unit Testing is important ?

Some people think unit tests is a waste of time. For them you should spend more time developing real code instead of doing unit testing. But I disagree. I am more at ease when unit test are running every day without failure. Indeed know my code works like I want. Personally I am faster to develop code because I am testing incrementally my developement. In my experience my code tend to have less bugs too.

I find that Unit testing has many advantages:

– Gain time when reproducing a problem / testing functionality before integration. Instead of launching the entire application to test your changes, you can just test the small part you did.

– Regression testing. The code is easier to refactor when there is lot of unit tests. If there are big changes in the code the unit test should help us to avoid regression.

Unit test are great, but if they are not run daily it is like they do not exist. That’s why it is very important to have a platform that launches them every day. For example for Java projects Jenkins is a popular platform.

Not only you should automatically test the code of programming languages such as Java ,Csharp, Javascript but as well script used for the installation of the product. Ideally the installation from scratch should be run daily on a machine.

Review of the book Pragmatic Programmer

Cover book of The Pragmatic Programmer

Comments about the book

To my mind this book is mind blowing. The first time i read it , it was a revelation. Thanks to it,  I grasped the use of systematic Unit Testing.

Before reading it, I was doing unit testing systematically while bug fixing. This was because of the strong policy of my first company.

After, I also understood many other programming practices. I realised that Unit testing or automatic testing is one of the most important tasks to do while programming. It allows automatic regression test and easier maintenance and bug fixing..

Another idea important to me : code only once policy. No duplication allowed. This is what i have been implementing so far .

Addtitionally, the use of design patterns is really useful to maintain the code . Before reading the book, as a young engineer getting from university, I barely knew what it was useful for. Design pattern is a skill you can implement whatever object language you use : C++,C# ,Java,etc… I have used it with these programming languages with success. It allows better extensibility and maintainability of the code.

Whenever there is a choice between different algorithms or possibility of extensions : use design pattern. The factory pattern is the one that I used the most in the end.

Advice for a young programmer

I would advice to a young engineer to start reading this book. Indeed, it introduces you with many skills you will need to learn if you want to be an excellent programmer. To my mind, the first things you will need to learn are :

  • To add systematically unit test in your code. If you want to go further: use TDD method.
  • Have a platform which launch your unit tests everyday . Be proactive: if it does not exist, suggest one to your manager. This is very important because without it your unit tests are not used. And therefore they are useless.
  • When you resolve a bug , first reproduce the bug. The best way is to reproduce the bug with a Unit test. Make the test failed at first,when the test is reproduced,the test should pass when you found the fix.
  • Use the ‘no duplication’ of code policy.  It is better to factorise the code to avoid duplication. In the long run the maintenance of the code is easier.
  • Use design patterns to make the code more extensible. When you develop a solution in programming, you should always think long term. For example: you need to develop a simple algorithm but maybe you will use a different one in the future. Use the factory method pattern in order to call easily a different algorithm in the future.
  • Learn MVC design pattern. It teaches how to separate the UI interface into several layers. It is important to have a user interface clearly separated into different modules in order to modify change of technology later.
  • Use Sonar to improve your coding skills. This tool when used with Jenkins, will show the problem in the code.

All these tips come from the book, therefore don’t hesitate to read it. It teaches lot of important skills that experienced programmer will only learn after years of development.