Monday, 24 June 2019

Debugging code - Identifying the bug



Julia Evans is a very smart woman in IT who creates very nice, funny and insight full comics, she calls 'zines', on Linux and Coding topics.

This morning I read she came up with a question that triggered me:


Last week I  realized I'm already 25 years in IT, after that my forced membership of a famous Dutch shooting club ended after 9 months (the kind of shooting club where you got free clothing, survival courses, and in my case also a truck-driving-license. Which other club offers that?). 

Anyway, during the years I discovered that despite of all the smart people I got to know and work with, this part of our work isn't obvious. In very many cases people seem to 'just do something'. No offense, but for developers it's often frustrating and just not fun to work on bugs or problems. And administrators that are confronted with a problem are often 'too busy with other stuff.' So they try something, don't find the thing, and at a later moment try something else. So, when I got involved I ask the obvious questions and in most cases I try out the same thing myself. Even though I do believe them, I want, I need,  to see the behavior with my own eyes.

By the way, I'm always reluctant to call it a bug. A bug is only a bug when you have reproduced it and based on common interpretation, together with the tester (if he found the issue), the functional/solution designer come to a consensus that the code does not do what it is supposed to. The functional specs are interpreted by both the tester and the developer. And in a certain way also the designer. It might be that the tester finds an anomaly, but that it is either a miss-interpretaton from him or a problem with the formulating of the specs. There are cases that the coder is right. But, of course, your program can work with an unexpected logic.


But, back to Julia's tweets:  they triggered me, so I jotted down some thoughts that I  got and are the basis of my search for issues.

To me it starts with identifying a case where it goes wrong, but equally importantly, together with a similar situation where it goes right. And, as far as possible, creating a unit test for both. Since, my work is mostly done on message processing platforms (Oracle SOA Suite, BPM Suite, Service Bus), I love it when a tester can hand me over a triggering message of the case and the involving response messages. I can then add them to my unit-test-set in SoapUI/ReadyAPI.
 

Then I add instrumentation (log lines, etc.) on key positions, that identify to which points the code is executed and what lines aren't reached. SOA Suite produces a flow trace of the execution. But often expressions are used that are quite complex one liners. I then split those up into several separate assignments to 'in between' variables. In Java, JavaScript, etc., I do not like complex one-liners. I prefer several variables for 'in between' values, and assignments with short expressions. That helps with line-by-line debugging.

Next, I iteratively narrow that gap between the point I can conclude the code reaches and the point I find not reached, until the statement or point of execution that fails can be identified.
In the log lines I add key variable values that are involved.


In very rare, very difficult, cases, I sometimes break down the code, cut away all the code that is not touched, until I get a minimal working Mickey Mouse (or in Dutch: Jip en Janneke) case. From there I build it up, and test iteratively in very small steps, until it breaks.

Also, very important, for difficult problems, I document very meticulously what I have done and concluded. My slogan here is: 'Deduction, my dear Whatson!' When having a problem, one can quickly come up with some potential causes and tests to check those. A unit test for a potential cause can go two ways, it can confirm or disapprove the suspicion. Both outcomes have consequences for the follow-up. Disaproving a potential cause, can strikethrough other potential paths as well. 

But, approving it, need additional steps to narrow down. I see it as a decision-tree to follow.

What I have found through the years, is that structurally document the steps done with the particular conclusions and the follow-ups is not quite obvious. But in many cases I found them important. Especially working in a Taskforce, or when I got hired to get involved in a case. In those cases the customer that hired you has the right to have something in hands that represents what he payed for.
I once was involved in a case that turned out to be a database bug. So I could not help the customer to solve it. But they where very pleased in the structured method I used to check out what could be the problem. And for those administrators and developers that got to do this as  a side job, besides there regular things: please do yourself a favor and document. I found Google Docs very usefull in this.


Oh, and by the way: I work with BPEL, BPMN, Oracle Service Bus, Java, Pl/Sql, XSLT, XQuery, Python/Jython/WLST, sometimes JavaScript, you name it. And actually, my way of structured code or systems analysis comes down to the same procedures. Regardless of technology.



Thursday, 6 June 2019

Weblogic 12.2.1.3 Signs SAML2 requests and responses with SHA-256

Today I reviewed a few responses on a 'What's new in Weblogic 12.2.1.3' question.
One of the responses mentioned the whats-new document.

Now, I'm not used to study these documents. But today I browsed through them and one thing caught my eye.

I did some implementations of Weblogic as a SAML2 Service Provider against MS ADFS. I'm even invited to do a talk 'SSO with ADFS for Apex Using Weblogic and ORDS: How I did it and Where I Tripped' at the UKOUG Southern Technology Summit 2019, july 2nd.

What's interesting here is that about 2 years ago I already wrote about my earlier experiences, and mentioned that Weblogic 12c did not support SHA-256 for the signing of SAML requests. So you had to configure ADFS to use SHA-1. In my latest implementation it stroke me that I did not have to force my ADFS counterpart to set that, at least I think I didn't. ADFS as you might expect for really some time now, uses SHA2 (SHA-256) as a default. But only today I saw that under Manageability Improvements -> Security is mentioned that Weblogic 12.2.1.3 also has SHA2 as a default now.

Knowing this will improve my talk greatly. I'm glad I saw this. It might seem to be a minor thing, but I think it's quite important.

I use Weblogic mostly as a FMW Infrastructure for SOA Suite, OSB, etc. And occasionally I do assignments with specifics like SAML2. If you're interested in what changed in a specific Weblogic version, I think it's important to know what you're looking for. Know the functionality that you're actively using or interested in.

Monday, 29 April 2019

Oracle Java Support: why should I pay for something that used to be free?


A few weeks ago, I discussed with a colleague about the new licensing model of Oracle Java.

Customers may have concerns about this, since until now a customer was used to be entitled to download Java Updates for free. At least I was.

During the discussion I posed a way of thinking that made sense to me, and that seems to be supported by document references.

For some time now you can download Open JDK, which is an open source reference implementation based on Oracle JDK, as I understand it. It states that it is a production ready. Although this story may be a bit more nuanced as I state here. In the past it was considered to be inferior to the Oracle JDK, whilst the Oracle JDK was also free. With the new release cycles, introduced with Java 9, Oracle committed to make OpenJDK as indistinguishable from OracleJDK as possible. So functional and security features are up to the level of Oracle JDK.

In short, if you don't want to pay for support you can go and use Open JDK. Or stay on your current version.

But, since Oracle is a Sales based organization, I'm not surprised if they want to be payed for delivering (Long Time) support on Java. Especially, when more and more software is from other vendors is based on Java, and when the competitors of Cloud platforms rely on it.

If you want to have support for Java, you should have a Support contract.

I mentioned already above, but what also changed, with Oracle 9, is the release cycle. Until Oracle Java 8, Oracle supported the JDK for a very, very long time. The globally, publicly available major Java versions were released in a few years pace. Java 7 was around for around 4 years, before Java 8 was released. Java 8 has been a round for 5, before Java 9 saw the light.

To get more in pace with the developments in the market, Oracle decided to start with half-yearly release cycles, starting with Java 9 in 2017. And now with every 6 months, a new Java version is released with new features. Features that do not make the cut, are delayed to the next release when they are ready. But the major Java version gets released. With that, also the support of the version is changed: the support on the release only lasts for the live span of the release, which is 6 months. To keep up with security and features, you to need to move on to the next major version, to keep supported. Currently we're at Java 12, from march '19.

If you can't keep up with that, Oracle provides a Long Time Support version, that is supported for time frame comparable of those of Java 6, 7 and 8. One of those half yearly releases are denoted LTS, and currently it is Java 11. It's most comparable with for instance RedHat Linux, providing Fedora as an open, publicly available version (like OpenJDK) and ReadHat Enterprise Linux, which is the LTS version.


Now, what if you have Licenses for Oracle products that rely on Java? Fusion Middleware, for instance, is only supported on Oracle Java, currently Oracle Java 8. You may have licenses for Weblogic, Coherence, Forms & Reports, etc. In those cases you have a restricted license of Oracle Java. Much like when you have an E-Business Suite, Siebel or any other Enterprise Information System of Oracle that uses the database. Then you can use the database, when you use it to support that setup. You cannot run custom code in it, do reporting on it or use the database in any other way.

The same counts for Java. If you run Weblogic, or have an application that uses Coherence, etc., you're entitled to download the updates for Java. See for instance this document about Restricted Oracle Java SE License in combination with Weblogic, or Support Entitlement for Java SE When Used As Part of Another Oracle Product. Also interesting: you can file support requests against that Oracle product, but not directly against Java SE, unless you have Java Support.

And, products like SQLDeveloper, sqlcl and ORDS are supported through the Database license, which also uses Java. So, having a Database license, you have support on SQLDeveloper and the Oracle Java, used by SQLDeveloper.

Notice that if you have a Weblogic License, but also have a custom java application not running in a Weblogic instance, it's not allowed to use the same JDK Updates! If the application uses HTTP to communicate with a Weblogic Server, for instance to call a REST or SOAP Service, you're not allowed to download updates for that Java Home.

Also, if you hava a custom java application that uses JDBC drivers to connect to a licensed Oracle database, then you're not allowed to download the Java updates. Oracle states that the JDBC drivers do not use an Oracle product-specific protocol.

I encountered a little while ago that JavaDB is not delivered with Oracle JDK anymore. I suppose that this is related to the changed licensing of Java.

I hope that this little article makes sense, to you and helps to understand the licensing model.

To sum up, the options you have
  1. Stay on the version you currently use, with out changes. If you can live or cope with being behind with security updates, this can be an acceptable choice.
  2. Keep up with the 6 months major version update pace, you can use OpenJDK. You keep up to date with the major versions and are secure.
  3. Stay on a LTS release and move with to another LTS at your own pace (but only for Oracle JDK).
This article have been simmering for a few weeks, since I've been busy with other stuff and I've got some review tips. But today I saw an article of Jeff Smith on the Oracle JDK with SQL Developer. So, this triggered me to update this article right away.

I did my best to blend my thoughts, with the review tips, and the notes of support. I put down what I think and learned in my own words, but I might have rephrased things a bit incorrectly.  Check out these more formal articles and statements:

Wednesday, 24 April 2019

Test Remote Asynchronous Request Response services

A few years ago, I described how you can test Asynchronous Request Response services.

The thing with Asynchronous Request Response services is, as I used to describe it, that they're in essence two complementary Request-Only (Fire and Forget) services. That is, the client submits a request to the Asynchronous Request Response service, and at a certain point waits for the response by listening to an endpoint.

To make this work, the responding Asynchronous Request Response service should be told, which endpoint it should call with the response and which correlation id should be used. The WS-Addressing standard is used for that. All nicely explained in the before mentioned article.

In most customer-cases the problem is that your Client SoapUI or ReadyAPI project should catch the response, but the service is running on a SOA Suite in the datacenter and is not allowed to get to your local machine.

MobaXterm makes it very easy to create a tunnel. You can have a remote tunnel, that enables a local listening endpoint, that forwards every request to a remote service. Very handy if you have a Vagrant project with only a NAT NetworkAdapter, where Vagrant enabled a ssh endpoint on port 2222. You can easily create a Local tunnel on port 7101, for instance, to the remote ssh session on port 2222, that enables you to get to the weblogic console on the remote VM running on http://darlin-vce:7101/console.

To create a tunnel, just open the MobaSSHTunnel - Grahpical port forwarding tool:
This will open:

You can create a new SSH tunnel or edit a current one using the cogs icon under settings. For instance, to be able to do the Local port forwarding to get to your Weblogic console on your Vagrant box, create a tunnel as follows:



On the left you can enter a local port. That is the port you can use on your localhost. On the top right you can enter an host and port for the address to post your request to (does not need to be localhost). Then bottom right you need to provide an ssh session. A bit inconvenient is that you can't select a session from the sessions pane. Provide a host, port and user to connect to your ssh server.

What happens is that MobaXterm creates an SSH session, and a local endpoint. Every thing posted to the local endpoint is posted on the remote server to the give address. In this case I can go on my browser and enter https;//localhost:7101/console and it will bring me to the Weblogic Console on my Vagrant box. Neat, isn't it?



To get the remote Async Service respond to your local machine, you can also create a we need a tunnel that works the otherway around: we need Remote Port Forwarding:

Configuring is similar to Local port forwarding, however, now on the remote server a listen endpoint is created, and everything that is posted to the localhost:7777 adress (in this example) is forwarded to the address entered on the local server. In this case it is forwarded to localhost:7777, but it could be something else.

In our ReadyAPI project I created a Groovy script as follows:
def testCase = testRunner.testCase
def env = testCase.testSuite.project.activeEnvironment.name
if (env != "o02-12c"  &&  env != "o02" ) {
  log.info "Environment: "+env+", so set callbackIp to "+InetAddress.localHost.hostAddress
  testRunner.testCase.setPropertyValue( "callbackIp", InetAddress.localHost.hostAddress)
} else {
  log.info "Environment: "+env+", so set callbackIp to localhost"
  testRunner.testCase.setPropertyValue( "callbackIp", "localhost")
}

In ReadyAPI you can define environments, with the project property activeEnvironment.name it can be queried.

If the environment points to one of our development environments, I set the callbackIp testcase property to "localhost". But for the default environment, I use InetAddress.localHost.hostAddress to get the local ip address. This will be the ip address of our CD/CI tool, that runs ReadyAPI from a script.

You can set the WS-Addressing ReplyTo address as follows, for instance:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:add="http://schemas.xmlsoap.org/ws/2003/03/addressing">
      <soapenv:Header>
       <add:ReplyTo>
         <add:Address>http://${#TestCase#callbackIp}:7777/MyMockResponseURI</add:Address>
      </add:ReplyTo>
   </soapenv:Header>
   <soapenv:Body>

Then this address is used to do the callback. Make sure the tunnel is started:

You can also have the tunnel auto started (with the blue man-running-icon) or auto-reconnected (with the purple lightning icon).

This may also be very relevant in testing services on Oracle SOA Cloud Service, or Integration Cloud.

Happy tunneling!

Thursday, 18 April 2019

Split your Vagrant provisioners

For a while now, I'm quite into Vagrant in combination with VirtualBox. A few years ago I started with trying to script FMW environments, and since my discovery, and resulting fancy, of Vagrant, I also created a project for creating and provisioning a SOA Suite box.

Until now, my project all had one shell-type provisioner looking like:
  config.vm.provision "shell", inline: <<-SHELL
    export SCRIPT_HOME=/vagrant/scripts
    . $SCRIPT_HOME/install_env.sh
    echo _______________________________________________________________________________
    echo 0. Prepare Oracle Linux
    $SCRIPT_HOME/0.PrepOEL.sh
    echo _______________________________________________________________________________
    echo 1. Create Filesystem
    $SCRIPT_HOME/1.FileSystem.sh
    echo _______________________________________________________________________________
    echo 2. Create Oracle User
    $SCRIPT_HOME/2.MakeOracleUser.sh
    #
    echo _______________________________________________________________________________
    echo 3. Java SDK 8
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/installJava.sh'
   SHELL

This seems quite simple, but for my SOA Suite box, I had quite a lengthy provisioner, that somehow failed at running the RCU and therefor with the creation of the domain.  There is a synchronization thingy with the database. The database is up, but at the time it reaches the RCU creation, it isn't able to connect. When running it seperately it works like a charm.

So, don't know how to solve that, but I want to re-provision only the part of the RCU and domain creation. Last night I fiddled around with it. Following the Vagrant Up basic usage explanation, you can create multiple provisioners with different names and different types. You can then force the provisioning for certain provisioners by type or by name.

I played around with that, because I couldn't get the syntax right. Although the explanation is proper, I wanted to have it slightly different and did not got it at first. Finally, I got it working.

Let's look into it.

First I split up my shell script, and found that I can put those in a variable. I now have a init script, that adapts the Linux OS, creates a new filesystem and creates an oracle user :
  $initScript = <<-SCRIPT
    export SCRIPT_HOME=/vagrant/scripts
    echo _______________________________________________________________________________
    echo 0. Prepare Oracle Linux
    $SCRIPT_HOME/0.PrepOEL.sh
    echo _______________________________________________________________________________
    echo 1. Create Filesystem
    $SCRIPT_HOME/1.FileSystem.sh
    echo _______________________________________________________________________________
    echo 2. Create Oracle User
    $SCRIPT_HOME/2.MakeOracleUser.sh
  SCRIPT

And one for installing the FMW software:
  $installFMWScript = <<-SCRIPT
    echo _______________________________________________________________________________
    echo 3. Java SDK 8
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/installJava.sh'
    echo _______________________________________________________________________________
    echo 4. Database 12c
    sudo runuser -l oracle -c '/vagrant/scripts/database/installDB.sh'
    echo _______________________________________________________________________________
    echo 5.1 SQLCL and SQLDeveloper
    sudo runuser -l oracle -c '/vagrant/scripts/database/installSqlcl.sh'
    echo _______________________________________________________________________________
    echo 5.2 SQLDeveloper
    sudo runuser -l oracle -c '/vagrant/scripts/database/installSqlDeveloper.sh'
    echo _______________________________________________________________________________
    echo 6. Fusion Middleware
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/installFMW.sh'
    echo _______________________________________________________________________________
    echo 6.1 Fusion Middleware - SOA
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/installSOA.sh'
    echo _______________________________________________________________________________
    echo 6.2 Fusion Middleware - SB    
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/installSB.sh'
    echo _______________________________________________________________________________
    echo 6.3 Fusion Middleware - OHS    
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/installOHS.sh'
    echo _______________________________________________________________________________
    echo 7. BPM Quickstart
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/installBpmQS.sh'
  SCRIPT

And one for configuring FMW, that is running the RCU and creating the domain:
  $configFMWScript = <<-SCRIPT
    echo _______________________________________________________________________________
    echo 8.1 Fusion Middleware - RCU SOA   
    sudo runuser -l oracle -c '/home/oracle/bin/startDB.sh'    
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/rcuSOA.sh'
    echo _______________________________________________________________________________
    echo 8.2 Fusion Middleware - Create Domain    
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/fmw1221_domain/1.recreateFMWDomain.sh'
    echo !!! TODO: Machine configuration update to use Plain - 5555
    echo !!! TODO: Modify domain creation and property naming to create machine in accordance to nodemanager config.
    echo _______________________________________________________________________________
    echo 8.3 Fusion Middleware - Modify Nodemanager     
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/fmw1221_domain/2.modifyNodeManager.sh'
    echo _______________________________________________________________________________
    echo 8.4 Fusion Middleware - Create Nodemanager service
    sudo runuser -l oracle -c '/vagrant/scripts/fmw/fmw1221_domain/3.createNodemanagerService.sh'
    #
  SCRIPT

Cool, so far, right?

Now, after that we need to define the 3 provisioners:

  config.vm.provision "init", type: "shell", inline: $initScript
  config.vm.provision "installFMW", type: "shell", inline: $installFMWScript
  config.vm.provision "configFMW", type: "shell", inline: $configFMWScript

These provisioners

  • init -> provisioning/config of Oracle Linux, creation of oracle user, etc. This will be about equal for every box.
  • installFMW -> installation of all FMW software.
  • configFMW -> run the RCU and create domein.
Having that in place, you can run a specific provisioner. For instance during up:
  • vagrant up --provision-with configureFMW
or when reloading the box:
  • vagrant reload --provision-with configureFMW
But the following also works:
  • vagrant provision --provision-with configureFMW
Another cool thing is that you also could set a run option on the provisioner.
  config.vm.provision "init", run: "once", type: "shell", inline: $initScript
  config.vm.provision "installFMW", type: "shell", run: "once", inline: $installFMWScript
  config.vm.provision "configFMW", type: "shell", run: "once", inline: $configFMWScript

The run option has the following possible values:
  • "once": this is actually the default, the provisioner is only executed at first up. Or if you force it to run as described above.
  • "always": the provisioner is executed at every up. This can be used for something you want to be done every time you do up. A good one would be to start the database.
  • "never": this one is interesting. This makes the provisioner optional. That means it won't be executed, unless you ask for it. A good one would be to drop the RCU and delete the domain. So that you can reprovision the repository and the domain.
Happy Vagrant Upping!