Troubleshoot Jenkins Subversion Migration

After migration a Subversion server to a different location I found that the SVN update was no longer working from a Jenkins instance that used that server. After a little
searching I found the solution in a Stackoverflow question.

It turns out that the SVNKit library that the Jenkins Subversion plugin does support TLS 1.0. To get it working I had the update the Apache site configuration to include SSLv3:

SSLProtocol -all +SSLv3 +TLSv1

For the stacktrace, see below:

The stacktrace from Jenkins:

org.tmatesoft.svn.core.SVNException: svn: OPTIONS /svn/repo/path failed
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:291)
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:276)
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:264)
        at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.exchangeCapabilities(DAVConnection.java:516)
        at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.open(DAVConnection.java:98)
        at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.openConnection(DAVRepository.java:1001)
        at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.testConnection(DAVRepository.java:97)
        at hudson.scm.SubversionSCM$DescriptorImpl.checkRepositoryPath(SubversionSCM.java:1966)
        at hudson.scm.SubversionSCM$DescriptorImpl.doCheckRemote(SubversionSCM.java:1900)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:282)
        at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:149)
        at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:88)
        at org.kohsuke.stapler.MetaClass$1.doDispatch(MetaClass.java:111)
        at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
        at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:563)
        at org.kohsuke.stapler.Stapler.invoke(Stapler.java:648)
        at org.kohsuke.stapler.MetaClass$6.doDispatch(MetaClass.java:241)
        at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
        at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:563)
        at org.kohsuke.stapler.Stapler.invoke(Stapler.java:648)
        at org.kohsuke.stapler.MetaClass$6.doDispatch(MetaClass.java:241)
        at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
        at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:563)
        at org.kohsuke.stapler.Stapler.invoke(Stapler.java:648)
        at org.kohsuke.stapler.Stapler.invoke(Stapler.java:477)
        at org.kohsuke.stapler.Stapler.service(Stapler.java:159)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:95)
        at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:87)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:47)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:84)
        at hudson.security.UnwrapSecurityExceptionFilter.doFilter(UnwrapSecurityExceptionFilter.java:51)
        at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
        at org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:166)
        at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
        at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125)
        at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
        at org.acegisecurity.ui.rememberme.RememberMeProcessingFilter.doFilter(RememberMeProcessingFilter.java:142)
        at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
        at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271)
        at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
        at org.acegisecurity.ui.basicauth.BasicProcessingFilter.doFilter(BasicProcessingFilter.java:173)
        at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
        at jenkins.security.ApiTokenFilter.doFilter(ApiTokenFilter.java:61)
        at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
        at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
        at hudson.security.HttpSessionContextIntegrationFilter2.doFilter(HttpSessionContextIntegrationFilter2.java:66)
        at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
        at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:76)
        at hudson.plugins.pwauth.PWauthFilter.doFilter(PWauthFilter.java:50)
        at hudson.plugins.pwauth.PWauthFilter.doFilter(PWauthFilter.java:37)
        at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:164)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:81)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:470)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
        at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190)
        at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:291)
        at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:776)
        at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:705)
        at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:898)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
        at java.lang.Thread.run(Unknown Source)
Caused by: org.tmatesoft.svn.core.SVNErrorMessage: svn: OPTIONS /svn/repo/path failed
        at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:200)
        at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:146)
        at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:89)
        ... 81 more
Caused by: org.tmatesoft.svn.core.SVNException: svn: OPTIONS request failed on '/svn/repo/path'
svn: Received fatal alert: handshake_failure
        at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:64)
        at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:51)
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:644)
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:285)
        ... 80 more
Caused by: org.tmatesoft.svn.core.SVNErrorMessage: svn: OPTIONS request failed on '/svn/repo/path'
        at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:200)
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:642)
        ... 81 more
Caused by: org.tmatesoft.svn.core.SVNErrorMessage: svn: Received fatal alert: handshake_failure
        at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:101)
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:389)
        ... 81 more
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(Unknown Source)
        at com.sun.net.ssl.internal.ssl.AppOutputStream.write(Unknown Source)
        at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
        at java.io.BufferedOutputStream.flush(Unknown Source)
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.sendData(HTTPConnection.java:229)
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPRequest.dispatch(HTTPRequest.java:166)
        at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:364)
    ... 81 more

Leave a Comment

Disable directory listing in Apache

Browse to the Apache configuration folder on disk. On Ubuntu this is for example /etc/apache2/sites-available. Edit the file default.

Look for the section that looks similar to:

<Directory /[some directory name]>

and you should see something like the following in the next line:

Options Indexes FollowSymLinks

To disable directory listing, just remove Indexes from this line or change Indexes to -Indexes to disable it.

Make sure to restart your Apache server after making the change to make it effective. That’s it! Directory listing should be disabled now by default!

If you want to enable directory listing for a specific directory added Index to the configuration for that directory.

Leave a Comment

Sudo rights to group

When setting up a new Linux system you also need to set up a way to gain root access for you standard user account. This is relatively easy to do following
these simple steps as root:

Edit /etc/sudoers and find the following line and uncommit it by removing the ‘#’ from the second line:

## Uncomment to allow members of group sudo to execute any command
#%sudo ALL=(ALL) ALL

Add the useraccount you wish to grant sudo access to to the sudo group, where user is the user account you want to give sudo access to:

usermod -a -G sudo [user]

When logged in as this user, issue the following command to gain root access using your own password:

[daan@system] sudo su -

Leave a Comment

Find hosts in network using nmap

Sometimes you need to know what the IP address is of a certain system in the network. For example if you plug in a new device and need to know
which IP address it got assigned. In Linux the tool nmap can be used to scan the IP range of your local network. With the right parameters
it will report on the different system it has found.

On the console execute the following command, where you replace 192.168.121 with the IP range of your own network:

sudo nmap -sP 192.168.121.0/24

This will output something similar to the example below from which, hopefully, you can deduce which of the systems below is your system:

dean@box:~$ nmap -sP 192.168.121.0/24

Starting Nmap 5.21 ( http://nmap.org ) at 2014-04-10 20:47 CEST
Illegal character(s) in hostname -- replacing with '*'
Nmap scan report for Network (192.168.121.1)
Host is up (0.0067s latency).
Nmap scan report for Box (192.168.121.103)
Host is up (0.000056s latency).
Nmap scan report for Molvin (192.168.121.109)
Host is up (0.0013s latency).
Nmap scan report for 192.168.121.160
Host is up (0.0038s latency).
Nmap scan report for GameConsole (192.168.121.166)
Host is up (0.039s latency).
Nmap scan report for Tablet (192.168.121.198)
Host is up (0.037s latency).
Nmap scan report for android-xxx (192.168.121.238)
Host is up (0.067s latency).
Nmap scan report for 192.168.121.253
Host is up (0.0081s latency).
Nmap done: 256 IP addresses (8 hosts up) scanned in 4.42 seconds

Leave a Comment

Remote debug a Tomcat Webapp

When developing a Tomcat web application I use the tomcat:deploy and tomcat-redeploy Maven targets to publish a new version of the webapp towards Tomcat. Not using
an IDE plugin which automatically connects to Tomcat forces me to do it manually. This is pretty easy!

catalina.sh / catalina.bat startup script

You can use the the catalina.sh (on Linux) or catalina.bat (on Windows) to control how Tomcat starts up. This script can be found in the bin folder of your Tomcat installation. Add the parameters jpda start to the script to start Tomcat
in its debug mode. In Windows, the complete command is:

catalina.bat jpda start

Under Linux it is:

./catalina.sh jpda start

Debugging

On startup Tomcat should now show a message similar to:

Listening for transport dt_socket at address: 8000

This means that Tomcat has started and listens at port 8000 for remote debug connections. You can now use your Java IDEs Remote Debug capabilities to connect remotely and set breakpoints and such in your IDE.

Leave a Comment

Let Jenkins ignore shell script return code

In a build preparation script I had a shell command that was executed. This command set some permissions, but would fail if the folder to set the permissions on would not exist. If the folder does not exist it would fail the build
because the permissions command would fail. I was looking for a way to ignore that, because the settings of the permissions would only fail if the workspace was cleaned and the file would be created later on in the build process
with the correct permissions.

In a Google Group post I found the solution, append || true to the command:

chmod 777 file.xml || true

Leave a Comment

Jenkins reports error on SVN update

One day a Jenkins server I use for Continuous Integration stopped updating code from SVN repositories. It reported an error ERROR: Failed to update https://svn.matuera.net/svn/project whilst throwing an SVNException.

In this post I describe how I was able to fix the problem and let the builds continue.

Stacktrace

The stacktrace that Jenkins reported was:

ERROR: Failed to update https://svn.daangemist.nl/svn/project
org.tmatesoft.svn.core.SVNException: svn: E175002: OPTIONS /svn/project failed
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:379)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:364)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:352)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.performHttpRequest(DAVConnection.java:708)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.exchangeCapabilities(DAVConnection.java:628)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.open(DAVConnection.java:103)
    at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.openConnection(DAVRepository.java:1018)
    at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.getRepositoryUUID(DAVRepository.java:148)
    at org.tmatesoft.svn.core.internal.wc2.SvnRepositoryAccess.createRepository(SvnRepositoryAccess.java:106)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgRepositoryAccess.createRepository(SvnNgRepositoryAccess.java:210)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgAbstractUpdate.updateInternal(SvnNgAbstractUpdate.java:144)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgAbstractUpdate.update(SvnNgAbstractUpdate.java:76)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgUpdate.run(SvnNgUpdate.java:38)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgUpdate.run(SvnNgUpdate.java:18)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgOperationRunner.run(SvnNgOperationRunner.java:20)
    at org.tmatesoft.svn.core.internal.wc2.SvnOperationRunner.run(SvnOperationRunner.java:20)
    at org.tmatesoft.svn.core.wc2.SvnOperationFactory.run(SvnOperationFactory.java:1235)
    at org.tmatesoft.svn.core.wc2.SvnOperation.run(SvnOperation.java:291)
    at org.tmatesoft.svn.core.wc.SVNUpdateClient.doUpdate(SVNUpdateClient.java:311)
    at org.tmatesoft.svn.core.wc.SVNUpdateClient.doUpdate(SVNUpdateClient.java:291)
    at org.tmatesoft.svn.core.wc.SVNUpdateClient.doUpdate(SVNUpdateClient.java:387)
    at hudson.scm.subversion.UpdateUpdater$TaskImpl.perform(UpdateUpdater.java:143)
    at hudson.scm.subversion.WorkspaceUpdater$UpdateTask.delegateTo(WorkspaceUpdater.java:153)
    at hudson.scm.SubversionSCM$CheckOutTask.perform(SubversionSCM.java:903)
    at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:884)
    at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:867)
    at hudson.FilePath.act(FilePath.java:909)
    at hudson.FilePath.act(FilePath.java:882)
    at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:843)
    at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:781)
    at hudson.model.AbstractProject.checkout(AbstractProject.java:1408)
    at hudson.model.AbstractBuild$AbstractBuildExecution.defaultCheckout(AbstractBuild.java:657)
    at jenkins.scm.SCMCheckoutStrategy.checkout(SCMCheckoutStrategy.java:88)
    at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:562)
    at hudson.model.Run.execute(Run.java:1603)
    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:46)
    at hudson.model.ResourceController.execute(ResourceController.java:88)
    at hudson.model.Executor.run(Executor.java:246)
Caused by: svn: E175002: OPTIONS /svn/project failed
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:208)
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:154)
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:97)
    ... 38 more
Caused by: org.tmatesoft.svn.core.SVNException: svn: E175002: OPTIONS request failed on '/svn/project'
svn: E175002: Received fatal alert: bad_record_mac
    at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:64)
    at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:51)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:754)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:373)
    ... 37 more
Caused by: svn: E175002: OPTIONS request failed on '/svn/project'
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:208)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:752)
    ... 38 more
Caused by: svn: E175002: Received fatal alert: bad_record_mac
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:109)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:505)
    ... 38 more
Caused by: javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1781)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1024)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1208)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:674)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:119)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.sendData(HTTPConnection.java:313)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPRequest.dispatch(HTTPRequest.java:168)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:460)
    ... 38 more
ERROR: Subversion update failed
java.io.IOException
    at hudson.scm.subversion.UpdateUpdater$TaskImpl.perform(UpdateUpdater.java:184)
    at hudson.scm.subversion.WorkspaceUpdater$UpdateTask.delegateTo(WorkspaceUpdater.java:153)
    at hudson.scm.SubversionSCM$CheckOutTask.perform(SubversionSCM.java:903)
    at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:884)
    at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:867)
    at hudson.FilePath.act(FilePath.java:909)
    at hudson.FilePath.act(FilePath.java:882)
    at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:843)
    at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:781)
    at hudson.model.AbstractProject.checkout(AbstractProject.java:1408)
    at hudson.model.AbstractBuild$AbstractBuildExecution.defaultCheckout(AbstractBuild.java:657)
    at jenkins.scm.SCMCheckoutStrategy.checkout(SCMCheckoutStrategy.java:88)
    at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:562)
    at hudson.model.Run.execute(Run.java:1603)
    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:46)
    at hudson.model.ResourceController.execute(ResourceController.java:88)
    at hudson.model.Executor.run(Executor.java:246)
Caused by: hudson.scm.subversion.UpdaterException: failed to perform svn update
    ... 17 more
Caused by: org.tmatesoft.svn.core.SVNException: svn: E175002: OPTIONS /svn/project failed
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:379)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:364)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:352)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.performHttpRequest(DAVConnection.java:708)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.exchangeCapabilities(DAVConnection.java:628)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.open(DAVConnection.java:103)
    at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.openConnection(DAVRepository.java:1018)
    at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.getRepositoryUUID(DAVRepository.java:148)
    at org.tmatesoft.svn.core.internal.wc2.SvnRepositoryAccess.createRepository(SvnRepositoryAccess.java:106)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgRepositoryAccess.createRepository(SvnNgRepositoryAccess.java:210)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgAbstractUpdate.updateInternal(SvnNgAbstractUpdate.java:144)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgAbstractUpdate.update(SvnNgAbstractUpdate.java:76)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgUpdate.run(SvnNgUpdate.java:38)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgUpdate.run(SvnNgUpdate.java:18)
    at org.tmatesoft.svn.core.internal.wc2.ng.SvnNgOperationRunner.run(SvnNgOperationRunner.java:20)
    at org.tmatesoft.svn.core.internal.wc2.SvnOperationRunner.run(SvnOperationRunner.java:20)
    at org.tmatesoft.svn.core.wc2.SvnOperationFactory.run(SvnOperationFactory.java:1235)
    at org.tmatesoft.svn.core.wc2.SvnOperation.run(SvnOperation.java:291)
    at org.tmatesoft.svn.core.wc.SVNUpdateClient.doUpdate(SVNUpdateClient.java:311)
    at org.tmatesoft.svn.core.wc.SVNUpdateClient.doUpdate(SVNUpdateClient.java:291)
    at org.tmatesoft.svn.core.wc.SVNUpdateClient.doUpdate(SVNUpdateClient.java:387)
    at hudson.scm.subversion.UpdateUpdater$TaskImpl.perform(UpdateUpdater.java:143)
    ... 16 more
Caused by: svn: E175002: OPTIONS /svn/project failed
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:208)
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:154)
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:97)
    ... 38 more
Caused by: org.tmatesoft.svn.core.SVNException: svn: E175002: OPTIONS request failed on '/svn/project'
svn: E175002: Received fatal alert: bad_record_mac
    at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:64)
    at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:51)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:754)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:373)
    ... 37 more
Caused by: svn: E175002: OPTIONS request failed on '/svn/project'
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:208)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:752)
    ... 38 more
Caused by: svn: E175002: Received fatal alert: bad_record_mac
    at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:109)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:505)
    ... 38 more
Caused by: javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1781)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1024)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1208)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:674)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:119)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.sendData(HTTPConnection.java:313)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPRequest.dispatch(HTTPRequest.java:168)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:460)
    ... 38 more

Initial research

At first I thought it had something to do with credentials or the Jenkins version, but checkout as the jenkins user from commandline did work. Also updating Jenkins did not resolve the issue.
Some research taught me that this problem only appears on Java 6 and is caused by the underlying SVNKit svn library used: 1, 2, 3 and 4.

The solution

In most posts the solution described is either upgrading the java version or by supplying an additional parameter at Jenkins startup to force SVNKit to work a bit differently. I do not know the exact effect it has
in SVNKit, but it does work. The Jenkins version I use on CentOS is started by a init-script in /etc/init.d/jenkins. I replaced the following line that starts Jenkins with:

JAVA_CMD="$JENKINS_JAVA_CMD $JENKINS_JAVA_OPTIONS -DJENKINS_HOME=$JENKINS_HOME -jar $JENKINS_WAR"

With:

JAVA_CMD="$JENKINS_JAVA_CMD $JENKINS_JAVA_OPTIONS -Dsvnkit.http.sslProtocols="SSLv3" -DJENKINS_HOME=$JENKINS_HOME -jar $JENKINS_WAR"

This solved the problem and allowed Jenkins to update normally.

Leave a Comment

Smarty 2 in PHP 5.5

When running a PHP powered website using Smarty 2 on a PHP 5.5 webserver it shows a deprecation error. This is caused by a deprecation of the /e parameter in the preg_replace function. Fortunately on the Smarty forum a topic is
available that provides a solution, without having to lower error_reporting in the server configuration.

Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in xxx/xxxx/php5/smarty/base/Smarty_Compiler.class.php on line 270 

The original code on line 270 of _Smarty_Compiler.php is:

/* replace special blocks by "{php}" */
$source_content = preg_replace($search.'e', "'"
                                    . $this->_quote_replace($this->left_delimiter) . 'php'
                                    . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'"
                                    . $this->_quote_replace($this->right_delimiter)
                                    . "'"
                                    , $source_content);

The culprit here is the /e modifier (PREG_REPLACE_EVAL)

The replacement to remove the deprecation notice is to use a preg_replace_callback:

$source_content = preg_replace_callback($search, create_function ('$matches', "return '"
                                   . $this->_quote_replace($this->left_delimiter) . 'php'
                                   . "' . str_repeat(\"\n\", substr_count('\$matches[1]', \"\n\")) .'"
                                   . $this->_quote_replace($this->right_delimiter)
                                   . "';")
                                   , $source_content); 

Leave a Comment

Second Crack Template Changes

An important change to the Second Crack template is to have a personal design that matches the goal of your blog. I wanted to keep it clean and simple and found a template design Simplesive that matches my preferences.

After modifying the template (originally made for Blogspot) I found that the Second Crack engine only allows you to display the full post on every page (overview and detail). You can circumvent this behavior by adding some changes to the template.
Besides that external links also need to be opened in an external window.

Open external links in a new window

My preference is to have links within the blog in the same window and to open external links in a new window or tab. Markdown does not have support for specifying a target for links, so I solved it using a piece of javascript I found.

//force external links to open in a new window, http://stackoverflow.com/questions/4425198/markdown-target-blank
var links = document.links;
for (var i = 0, linksLength = links.length; i < linksLength; i++) {
   if (links[i].hostname != window.location.hostname) {
       links[i].target = '_blank';
   } 
}

Read more function

The template must be modified in order to display it in a shorter version, or the full version. Every post must also include a marker (). On an overview page this marker and everything below it will be removed and replaced by a read more link.
On a detail page this marker is removed and the entire post is displayed. A detail page in Second Crack has the $pageType post

Template function

<?php if( !function_exists('tpl_getPostContents') ) { 
    function tpl_getPostContents( $postBody, $pageType, $permaLink, $moreLink = '<p class="readmore"><a href="%s">Read on</a></p>') {
    $excerptOnly = $pageType !== 'post';

    $morePatternPart = '<!---\s*more\s*--->';

    if( !$excerptOnly ) {
        //remove the comment from the source
        return preg_replace('/' . $morePatternPart . '/ms', '', $postBody);
    } else {
        $matches = null;
        if( preg_match('/^(.*)' . $morePatternPart . '/ms', $postBody, $matches) ) {
            return $matches[1] . sprintf($moreLink, $permaLink);
        } else {
            return $postBody; //there is no more part
        }
    }
} } ?>

The function starts with a check if the function already exists. This is necessary because for every page the Second Crack generates the template is included.

Display post

<div class="post-outer">
    <div class="post hentry">
        <h3 class="entry-title"><a href="<?php echo h($post['post-permalink-or-link']) ?>"><?php echo h($post['post-title']) ?></a></h3>
        <span class="post-timestamp">By Daan at <?php echo date('F j, Y', $post['post-timestamp']) ?></span>
        <div class="post-body entry-content">
            <?php echo tpl_getPostContents($post['post-body'], $content['page-type'], $post['post-permalink-or-link']); ?>
            <div class="post-footer-line post-footer-line-2"><span class="post-labels">
                Tags: <?php $tagCount = count($post['post-tags']); $iter = 0; foreach( $post['post-tags'] as $tag => $value ) { ?>
                    <a href="/tagged-<?php echo $tag; ?>.html" rel="tag"><?php echo $tag; ?></a><?php if( $iter < $tagCount-1) echo ', '; ?> 
                <?php $iter++; } ?>
                </span>
            </div>
        </div>
    </div>
</div>

In the post the function is used to display the contents.

RSS template Change

In the RSS feed I use the same function tpl_getPostContents to display the RSS contents. I do not include the function itself there, the main.php template file already defines the function.

Core change

I noticed that when validating the generated rss.xml that there were warnings about the timestamp in the post_date field. To fix this I updated the Post.php file with the following change:

In Post.php: function array_for_template() I changed this line:

'post-rss-date' => date('D, d M Y H:i:s T', $this->timestamp),
to:
post-rss-date' => date('r', $this->timestamp),

The difference is that the r modifier in the PHP date() function generates an RFC 2822 formatted date, which is a better format in the XML than the original date format in the Second Crack code.

Leave a Comment

Running Second Crack on a nginx server

This blog is running on an nginx webserver. The Second Crack page contains a .htaccess file which rewrites the permalinks to html files. For example the URL http://www.example.com/2014/01/20/example-blog-post is internally rewritten to http://www.example.com/2014/01/20/example-blog-post.html. On an nginx server .htaccess files do not work (at least not on a default configuration) so this needs to be incorporated in the site configuration.

Update April 26th 2015, updated nginx configuration to support index.html index file on subfolders (in try try_files statement).

Server config file

The server configuration below is based upon an excellent post by Adufray, I only improved upon it. Most elements are pretty standard, I will only explain the ones which are not as obvious.

server {
	listen 80;
	server_name www.daangemist.nl;
	root /srv/http/webapps/www.daangemist.nl;
	index index.html;

	rewrite ^/feed/$ /rss.xml permanent;

	types {
		application/rss+xml xml;
	}

	location ~ ^/. {
		default_type text/html;
		try_files $uri $uri/index.html $uri.html =404;
		error_page 404 /404.html;
	}
}

Rewrite

This line tells nginx to return a 302 Redirect HTTP response if someone requests the /feed/ URL. It is in place for the migration from WordPress to Second Crack.

Types

The RSS feeds are XML documents, this directive tells nginx to return a Content-Type: application/rss+xml header instead of text/xml for the RSS files.

Location

_tryfiles is the nginx counter part of the .htaccess _modrewrite directive in the .htaccess file on Apache. It tells nginx to look for a .html file for every URL it cannot find. I have added the =404 to prevent a redirect loop, this occurred in combination with the error_page directive.

2014/01/03 23:23:43 [error] 21252#0: *3 rewrite or internal redirection cycle while internally redirecting to "/favicon.ico.html.html.html.html.html.html.html.html.html.html.html", client: 62.140.132.196, server: www.daangemist.nl, request: "GET /favicon.ico HTTP/1.1", host: "www.daangemist.nl"

The $uri/index.html is to support subfolders, for example by accessing the monthly index via http://site/blog/2014/02/.

_errorpage tells nginx to open a custom 404 page if a post or page cannot be found, as explained in the WordPress migration post.

Leave a Comment