Author Archive: dfighter1985

DevOps is not a job title!

Sadly I see it more and more often. I know many people, mostly recruiters, would beg to differ, but DevOps is still not a job title.

It’s a culture of cooperation, and automation within your organization. So it’s not one person, or a group of persons. It’s your entire organization that should be doing DevOps.

At the core it’s cooperation between developers and operations people to enable your organization to work smoother, develop your services faster with less problems. So it’s not a single engineer or a group of engineers who automate things. It’s your developers and operations people working together, automating together in cooperation.

It was all popularized by John Allspaw and Paul Hammond of Flickr, with their Velocity 09 presentation “10+ Deploys Per Day: Dev and Ops Cooperation at Flickr”. See for yourself:

Advertisements

“Could not find a JavaToKotlinConversionProvider” after upgrading to Android Studio 3.3

Today I dared update to Android Studio 3.3 and as a reward I got a big, fat exception when trying to create a new project:

java.lang.RuntimeException: Could not find a JavaToKotlinConversionProvider, even though one should be bundled with Studio

After some experimenting I figured out the solution which is fairly simple: You just need to (re)enable the Kotlin plugin.

From the main screen you just need to go to Configure -> Plugins, tick Kotlin, click OK and then restart when it is offered.

…and that’s it, you’re all set and you can now create new projects again! Happy coding! šŸ™‚

Stop Nagios worker syslog spam on Ubuntu

We have Nagios running on one of our dev servers at work, and despite syslog logging being set to off in it’s config file it’s been spamming syslog with worker messages which is quite annoying.

Fortunately Ubuntu uses rsyslog as it’s default syslog, which is capable of redirecting log messages based on user defined filters. So I decided to get rid of this annoying problem and created that filter. Created a file /etc/rsyslog.d/49-nagios.conf with the following contents

:syslogtag, contains, “nagios” /var/log/nagios.log
& stop

After restarting rsyslog with

sudo service rsyslog restart

The problem is now solved, now it redirects those messages into the specified log file instead. šŸ™‚

Netbeans 8.1 “No tests executed”

Recently I’ve started to learn and practise unit testing in Java using JUnit to improve my productivity and confidence in my own code. Netbeans is quite useful for tests too, because it automates many things while writing and running the tests. However today I noticed something weird: I wrote some tests and I could run them just fine by themselves from the projects widget using the context menuitem “test file”, however when I wanted to “test project” from the run menu, Netbeans said “No tests executed” in the test window. I started digging and unfortunately I couldn’t find anything useful. However I noticed that in all the examples the test classes were called XYZTest, while my test classes are were named TestXYZ. I tried to rename then and guess what? Renaming them solved the problem. So to sum my experiences up:

If you want Netbeans to find and run your test classes name them like this: XYZTest. Where XYZ can be of course an arbitrary string that is legal in a class name in Java.

SocketTimeoutException in servlet running in Tomcat 7 behind an Nginx 1.10.3 reverse proxy

We have a digital object repository called DSpace at work, and we use the SWORDv2 protocol to deposit digital object into it. DSpace GUI and it’s SWORDv2 endpoint runs as servlets in a Tomcat container, and it’s all behind Nginx acting as a reverse proxy.

The other day one of my co-workers wanted to deposit a larger digital object package ( 8 GB ) into the repository, but unfortunately it failed because the servlet kept throwing SocketTimeoutException while it was reading the data being deposited, so I had to investigate and solve the problem.

java.net.SocketTimeoutException: Read timed out
java.net.SocketInputStream.socketRead0(Native Method)
java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
java.net.SocketInputStream.read(SocketInputStream.java:170)
java.net.SocketInputStream.read(SocketInputStream.java:141)
org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:535)
org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:504)
org.apache.coyote.http11.InternalInputBuffer$InputStreamInputBuffer.doRead(InternalInputBuffer.java:566)
org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:137)
org.apache.coyote.http11.AbstractInputBuffer.doRead(AbstractInputBuffer.java:339)
org.apache.coyote.Request.doRead(Request.java:438)
org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:290)
org.apache.tomcat.util.buf.ByteChunk.substract(ByteChunk.java:449)
org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:315)
org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:167)
org.swordapp.server.SwordAPIEndpoint.storeAndCheckBinary(SwordAPIEndpoint.java:197)
org.swordapp.server.SwordAPIEndpoint.addDepositPropertiesFromBinary(SwordAPIEndpoint.java:388)
org.swordapp.server.CollectionAPI.post(CollectionAPI.java:160)
org.swordapp.server.servlets.CollectionServletDefault.doPost(CollectionServletDefault.java:48)
javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

I read the Tomcat and DSpace logs but it revealed nothing. I noticed that DSpace had some interrupted deposits in it’s upload directory. All of the files were of size 2 GB, which was suspicious but I couldn’t figure out why at first, because I couldn’t see and find any limit that would explain why it should die at just 2 gigs.

I am not an Nginx expert, but I enabled debug logging and started reading logs. Unfortunately at first sight it didn’t reveal anything, I saw no errors, only that Tomcat returned 500 while depositing, that’s when the SocketTimeoutException was raised. However some lines caught my attention anyways.

2018/07/18 09:27:55 [debug] 4273#4273: *1 sendfile: @0 2147479552
2018/07/18 09:27:55 [debug] 4273#4273: *1 sendfile: 2147479552 of 2147479552 @0

That big integer was quite suspicous, and after doing some simple math I figured that 2147479552 twice divided by 1024 is 2048. Which means this could be a byte count. This made me start thinking. After sending this much data and some wait Tomcat sent 500 with that exception, so I figured it’s worth looking into. I started digging in Nginx’s source code and found a comment block and a constant below it:

/*
* On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit
* offsets only, and the including <sys/sendfile.h> breaks the compiling,
* if off_t is 64 bit wide. So we use own sendfile() definition, where offset
* parameter is int32_t, and use sendfile() for the file parts below 2G only,
* see src/os/unix/ngx_linux_config.h
*
* Linux 2.4.21 has the new sendfile64() syscall #239.
*
* On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter
* more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL,
* so we limit it to 2G-1 bytes.
*/

#define NGX_SENDFILE_MAXSIZE 2147483647L

After some further digging I realized that this sendfile() call is the default network I/O implementation of Nginx, but it can be turned off by setting

sendfile off;

in the http scope of the Nginx config file. As I suspected this solved the problem, and we could deposit the packages without problems. Now as a short summary here’s what this is about and what happened:

sendfile() is an I/O call that transfers data between file descriptors without having to first read the data into RAM, therefore it’s faster than the traditional solution of reading from the source, storing in RAM then writing to the destination. This is by default enabled in Nginx and this is what among other solutions makes Nginx a fast web server. However it has a limit of 2 GB. So when my co-worker was depositing his package, Nginx accepted the deposit, and sent it to Tomcat. The trouble was that it wouldn’t send all data. When it finished with the 2GB part of the 8 GB size file it just stopped, while Tomcat was still waiting for the rest of the data. After a short while it timed out, and returned an HTTP code of 500 to Nginx. Turning off sendfile() fixes this, as Nginx can now send all the data, however this makes network I/O slower.

Drupal 8 entity access permission problems

Sometimes even when you think you’ve given all the correct permissions to a user role Drupal still denies access to a node. This happened to me this week at work unfortunately and I spent some time digging through Drupal 8’s codebase to track down where and why it does this. So in case someone else has this problem as well, these calls in order are the interesting code parts to check out.

AccessManager::check
AccessManager::performCheck
EntityAccessCheck::access
Node::access
ContentEntityBase::access
EntityAccessControlHandler::access

In my case from the bottom of this stack turned out to be one of the modules that denied access. EntityAccessControlHandler::access method calls ModuleHandler::invokeAll to query the modules if they will allow access. Let’s see that Drupal method in version 8.3.x:

public function invokeAll($hook, array $args = []) {
$return = [];
$implementations = $this->getImplementations($hook);
foreach ($implementations as $module) {
$function = $module . ‘_’ . $hook;
$result = call_user_func_array($function, $args);
if (isset($result) && is_array($result)) {
$return = NestedArray::mergeDeep($return, $result);
}
elseif (isset($result)) {
$return[] = $result;
}
}

return $return;
}

As we can see it calls a hook, and passes the arguments that go into the method. The hooks are the following typically:

entity_access
node_access

The arguments are the following:

[ $entity, $operation, $account ]

Operations in case of access can be the following:

create
read
update
delete

Using these information we can filter the calls and list which module(s) deny access and then check out what their problem is

Tomcat 7 servlet context parameters

In desktop applications we typically configure our application by reading a config file, and using the values found.

In a Java web application however there’s a better way, because there’s already a config file we can use, and this is the web.xml file, where we can place the so called context init parameters, that are loaded during the web application’s startup. In this article I’m going to show how this works.

There are 3 things we must do to make this all work

  • Create a so called ContextListener subclass that will listen to events such as context initialization (servlet startup).
  • Tell Tomcat we have such a listener class and that it should tell it about such events, by referencing our class in the web.xml file
  • Place the parameters and values in the web.xml file

This is how a ContextListener class looks like:

package something.something.darkside;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;

public class ContextListener implements ServletContextListener
{
@Override
public void contextInitialized( ServletContextEvent event )
{
final ServletContext context = event.getServletContext();
final String dbdriver = context.getInitParameter( “dbdriver” );
final String dburl = context.getInitParameter( “dburl” );
}

@Override
public void contextDestroyed( ServletContextEvent event )
{
}
}

As we can see the class has 2 methods that need to be implemented, the contextInitialized and contextDestroyed events. We can read the context parameters in the contextInitialized class and then do whatever we want with them.

Let’s now see the relevant parts of such a web.xml file:

<?xml version=”1.0″ encoding=”UTF-8″?>
<web-app xmlns=”http://java.sun.com/xml/ns/javaee&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&#8221;
version=”3.0″>
<context-param>
<param-name>dbdriver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</context-param>
<context-param>
<param-name>dburl</param-name>
<param-value>jdbc:mysql://localhost/database</param-value>
</context-param>
<listener>
<listener-class>something.something.darkside.ContextListener</listener-class>
</listener>

As we can see we have 2 parameters here dbdriver, and dburl, which are database connection configuration parameters in this case. Also we have the context event listener class references. If we restart Tomcat now when starting up the servlet it will tell the context listener about the startup and it can read the parameters.

That’s it. It’s this simple!

Authenticating users against Active Directory with PHP

A co-worker of mine asked how this can be done, since I’ve already had some experience querying AD with Java and PHP. It’s been some time ago so I had to think about a little but then I realized it’s easy. Just use LDAP bind!

Consider the following PHP code snippet:

$ldaphost = ‘ldap://dc.mycompany.local’;
$ldapport = 389;

$user = ‘DOMAIN\user’;
$password = ‘password’;

$ldapconn = @ldap_connect( $ldaphost, $ldapport );
if( $ldapconn )
{

ldap_set_option( $ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3 );
ldap_set_option( $ldapconn, LDAP_OPT_REFERRALS, 0 );

$ok = @ldap_bind( $ldapconn, $user, $password );
if( $ok )
{
ldap_unbind( $ldapconn );
}
else
{
echo ‘Failed to bind to LDAP server:’ . “\n”;
echo ldap_error( $ldapconn ) . “\n”;
}
}
else
{
echo ‘Failed to connect to LDAP server’ . “\n”;
}

It is important to prefix the user’s name with the domain otherwise it won’t accept it and obviously in real life you’d want to use LDAPS and not send the password over the wire in clear text, but the basic idea is the same.

Remote debugging Tomcat7 servlets with Netbeans

At work we still use Tomcat 7 in production and I needed to set up debugging for various development systems. This article shows how to enable Tomcat 7 remote debugging

Enabling Tomcat 7 remote debugging via JDWP

Linux

I use Ubuntu 16.04 LTE so I’ll use that in the example, but other distros will not be that much different, except for the path and (re)starting the service of course.

  • Edit or create the file /usr/share/tomcat7/bin/setenv.sh and put in the following content:

    export JAVA_OPTS=”-Xdebug \
    -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n”

    Note: Obviously if the file already exists and it already has some content, then just add the parameters instead of adding the entire line.

  • Restart Tomcat

    sudo service tomcat7 restart

Windows

  • Go to the Tomcat binary directory, which is by default

    c:\Program Files\Apache Software Foundation\Tomcat 7.0\bin

  • Start the program Tomcat7w.exe
  • Switch to the java tab and add the following lines to the Java options textbox:

    -Xdebug
    -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n

    Note: It is important that each of the parameters should be added on separate lines, and that lines should have no whitespaces in the end!

  • Restarts Tomcat 7

    net stop tomcat7
    net start tomcat7

Attaching Netbeans debugger to Tomcat 7

Now that we have Tomcat running with the remote debugging on we can attach Netbeans to debug.

  • Click debug – attach debugger, a dialog box will appear
  • Select Java Debugger (JPDA) as the Debugger
  • Select SocketAttach as Connector
  • Fill in host / IP address to the host field
  • Fill in port to the Port field, in this example the port is 8787, but obviously it can be any non-taken port
  • Click OK
  • If everything went OK the debugging tab should show up showing the running threads

…and that’s it! Happy bug hunting!

Achievements of modern technology

It is often said that one picture can tell a thousand words. This is a picture of the tablet I bought in 2015 browsing the boot floppy I created in 1998. Yes that was 18 years ago.

img_20161007_185650