Showing posts with label error. Show all posts
Showing posts with label error. Show all posts

Saturday, March 17, 2012

Oh un-holy grails ...

It has been a while... which isn't to say I haven't been running to a myriad of issues, but I just haven't had the time to update.  But this one, egads. I could not help but describe and hopefully save someone out there in the interwebs many hours and tears.

Our adventure today begins with a seemingly simple task.  Upgrading the Grails version for a project.  The project was previously on Grails 1.3.7, and we are upgrading/updating/whichever it to 2.0.  For a point of reference, here is the setup/environment :
  • This a fairly large code base containing many other modules.  
  • We are using maven
  • My IDE of choice is Eclipse Helios (64bit)
  • We have a 'local' nexus that proxies stuff for us
In addition to the base Grails, we have the following plugins installed:
  • Spring-Security-Core
  • Spring-Security-Ui
    • Mail
    • JQuery
    • JQuery-ui
    • famfamfam
  • tomcat
  • hibernate
  • jaxrs
And we also have the following dependencies:
  • Spring-Security-Core 
  • Spring-Security-Web
Note that there are two separate Spring-Security-Core, one is a plugin and one is a dependency to be added in the pom.xml.  Another note, it has been many months since we set up our Grails project, and my memory just isn't what it used to be.

Here's an overview of what this blog entails:
  • Where are the jars?
  • Multiple versions of grails in the same workspace
  • Wait, I need to INSTALL grails as well??
  • Grails "upgrade" command doesn't work with maven-ized projects
  • Trouble re-installing the JAXRS plugin
  • Some final thoughts
Issue #1 - Where are the jars?
My first problem will probably be moot for most people now.  I could not get the updated jars from our local nexus.  It took a little searching and I came across this:  Grail 2.0 jars not available through maven central.  Which of course explains why our nexus didn't pull it in.  The reason this is moot now is that Grails 2.0.1 is available through maven central.  So I was able to grab the jars for 2.0.1 fine.  But for future reference, if you experience trouble pulling in the jars for new versions of Grails ... check to see if they even exist in your nexus or maven central.  If not, you can grab them from Grails' repo: http://repo.grails.org/grails/core.

Issue #2 - Multiple versions of grails in the same workspace.
Since this is a major release of Grails, there are many things that have been changed and therefore our code needs to be changed to work with the Grails.  Grails does provide a nice* write-up of how to upgrade your code here: Upgrading From Previous Versions of Grails.

*Since I have only just resolved my issues with getting started, I haven't yet had a chance to follow their write-up, but at a glance, it looks fairly detailed.  Whether or not it is detailed enough, I will find out soon.

Because this is potentially going to perturb our code base with all the changes, I am working the upgrade in a branch that contains only this module.  Seems like a sound plan, right?  At this moment, I have our entire code base open in eclipse and I have this branch open.  As soon as I change the POM to reference 2.0.1, and eclipse does its auto build thing to pick up this change ... the bad thing happens.  Namely, eclipse exits all by it's lonesome, with no message or anything.  Just, one minute it's building ... next minute it's gone.

What happened?  Since I'm on a Mac, I opened up the console to take a look at what it says.. and it says a lot:
(Listing 1)
ar 16 11:31:16 dhc019746 [0x0-0x1f51f5].org.eclipse.eclipse[5701]: /Users/frog/Documents/workspaceNew/caffiendFrog-webapp-service-BRANCH/plugins/spring-security-core-1.2.7.2/src/java/grails/plugins/springsecurity/DigestAuthPasswordEncoder.java:88: cannot find symbol
Mar 16 11:31:16 dhc019746 [0x0-0x1f51f5].org.eclipse.eclipse[5701]: symbol  : variable Hex
Mar 16 11:31:16 dhc019746 [0x0-0x1f51f5].org.eclipse.eclipse[5701]: location: class grails.plugins.springsecurity.DigestAuthPasswordEncoder
Mar 16 11:31:16 dhc019746 [0x0-0x1f51f5].org.eclipse.eclipse[5701]:   return new String(Hex.encode(digest.digest(s.getBytes())));
Mar 16 11:31:16 dhc019746 [0x0-0x1f51f5].org.eclipse.eclipse[5701]:                     ^
Mar 16 11:31:16 dhc019746 [0x0-0x1f51f5].org.eclipse.eclipse[5701]: /Users/frog/Documents/workspaceNew/caffiendFrog-webapp-service-BRANCH/plugins/spring-security-core-1.2.7.2/src/java/org/codehaus/groovy/grails/plugins/springsecurity/AbstractFilterInvocationDefinition.java:179: cannot find symbol
.... (Lots more errors along the same lines, cannot find symbols) ...
Mar 16 11:31:16 dhc019746 [0x0-0x1f51f5].org.eclipse.eclipse[5701]: 100 errors
Mar 16 11:31:16 dhc019746 [0x0-0x1f51f5].org.eclipse.eclipse[5701]: 1 error
Mar 16 11:31:16 dhc019746 com.apple.launchd.peruser.503[184] ([0x0-0x1f51f5].org.eclipse.eclipse[5701]): Exited with exit code: 1
It took me quite a lot of frustration, many hours, to realize that the problem was that because the two versions of grails is so different, they can not coexist happily, at least not without some tweaking.  There is a nice little script available here that does the switching automagically based on what version of grails your project needs.  You only need to a little bit of setup, namely setting an environment variable to point to a default version of grails, and to have both versions of grails in the same folder.  For example, this is what I did:

  1. I decided to use 1.3.7 as my default, so I set my $GRAILS_HOME to point to that in my ~/.bashrc file:
    • (Listing 2)
      export GRAILS_HOME=/opt/grails-1.3.7
  2.  I unzipped and placed both versions under /opt:
    • (Listing 3)
      frog@hostname:/opt$ ls
      total 16
      drwxr-xr-x  14 frog   staff   476 Mar 16 14:37 .
      drwxrwxr-t  37 root   admin  1326 Mar 16 14:20 ..
      drwxr-xr-x  20 frog   admin   680 Nov  2 15:40 grails-1.3.7
      drwxr-xr-x@ 21 frog   staff   714 Feb 14 16:22 grails-2.0.1
      drwx------@  8 frog   staff   272 Mar 16 14:37 grails-docs-1.3.7
      drwx------@ 16 frog   staff   544 Mar 16 14:36 grails-docs-2.0.1
      drwxr-xr-x   3 frog   staff   102 Mar 16 14:27 multi-grails
      
  3. I put the script in it's own folder (multi-grails) in the same folder with the grails version and added that information to the $PATH environment variable in the ~/.bashrc file:
    • (Listing 4)
      export PATH=/opt/multi-grails/:$PATH
    Maybe this is obvious to more experienced developers, but I've never had this problem before and I know I've worked with multiple versions of libraries opened in the same workspace before.  Well, as it turns out ... this is because of my next issue.

    Issue #2a - Wait, I need to INSTALL grails as well??
    This is a painful thing for me to admit, and maybe it's obvious in the documentation on grails and I was just trying to do things too quickly and didn't notice.  But I completely forgot I had installed grails on my machine.  I just assumed it was a plugin like any other. No, no, no. You need to install grails.  And by install grails, I mean:
    1. Download the binary zip of the version you want (http://grails.org/Download)
    2. Unzip.
    3. C'est Fin.
    Face, palm, anyone?
      Issue #3 - Grails "upgrade" command doesn't work with maven-ized projects
      Alright, now that I can actually VIEW my code in eclipse, I can start the upgrading process.  Grails provides a nice "upgrade" command to make life easier.  It is simply "upgrade".  To use this command on the command line with the mavenized grails commands:
      (Listing 5)
      mvn grails:exec -Dcommand=upgrade
      Simple, right? Ah, but no. Again, that would be too easy.  What you end up with if you try this on the command line is something along the lines of, after lots of downloading of whatever other dependencies your project has:
      (Listing 6)
      NOTE: Your application currently expects grails version [2.0.1], this target will upgrade it to Grails 1.3.7 ...
      
              WARNING: This target will upgrade an older Grails application to 1.3.7.
              Are you sure you want to continue?
                          (y, n)
      y
         [delete] Deleting directory /Users/frog/Documents/workspaceNew/blog/target/classes
         [delete] Deleting directory /Users/frog/Documents/workspaceNew/blog/target/resources
         [delete] Deleting directory /Users/frog/Documents/workspaceNew/blog/target/test-classes
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD FAILURE
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time: 1:29.344s
      [INFO] Finished at: Sat Mar 17 19:25:48 EDT 2012
      [INFO] Final Memory: 32M/81M
      [INFO] ------------------------------------------------------------------------
      [ERROR] Failed to execute goal org.grails:grails-maven-plugin:1.3.7:exec (default-cli) on project caffiendFrog-webapp-service: Unable to start Grails: java.lang.reflect.InvocationTargetException: : /Users/frog/Documents/workspaceNew/blog/null/src/war not found. -> [Help 1]
      [ERROR] 
      [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
      [ERROR] Re-run Maven using the -X switch to enable full debug logging.
      [ERROR] 
      [ERROR] For more information about the errors and possible solutions, please read the following articles:
      [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

      If you look at the end of line 17 above, you can see it is looking for: /blah/blah/null/src/war.  What the heck, why is it looking for null, and where did that even get specified?  According to this blog, there is some problem with resolving the environment path and maven and grails.  Long story short, it doesn't work.  You can't (at this time at least) use the upgrade grails command on a maven-ized project.

      So now what?  Now you do the upgrade manually.  The above mentioned blog entry has instructions as well.  Here is what I did, in a little bit more detail.  Note that some of the steps I'm not sure are 100% necessary, but I was getting tired of eclipse choking on me.

      1. Exit eclipse.
      2. Navigate to the directory of your project
      3. Using your favorite text editor, manually edit the pom.xml file to change the grails version to 2.0.1.  Note that in our case, we have declared a property at the top of the pom.xml that is used in all the grails related dependencies for consistency.
      4. Using your favorite text editor, manually edit the application.properties to change the app.grails.version to 2.0.1.
      5. Make a note of all the plugins that are listed in the application.properties file.  For example, here are the plugins that our module uses:
        • (Listing 7)
          plugins.famfamfam=1.0.1
          plugins.hibernate=2.0.1
          plugins.jaxrs=0.6
          plugins.jquery=1.7.1
          plugins.jquery-ui=1.8.15
          plugins.mail=1.0
          plugins.spring-security-core=1.2.7.2
          plugins.spring-security-ui=0.2
          
        • As I mentioned earlier, it has been a while since we first set this up, so I didn't even remember all the plugins we were using.
      6. Using the command line, uninstall each of these plugins. The name of the plugin to pass in for the command is what appears after the '.' in your list.
        • (Listing 8)
          mvn grails:exec -Dcommand="uninstall-plugin" -Dargs="famfamfam"
      7. Now, install the very same plugins, this time the install will pull in the updated versions of your plugins.
        • (Listing 9)
          mvn grails:exec -Dcommand="uninstall-plugin" -Dargs="famfamfam"
      Issue #4 - Trouble re-installing the JAXRS plugin
      One of the plugins that we use is jaxrs ...which has a dependency on some restlet.org packages.  For some odd reason, when trying to re-install the plugin, I keep getting errors about inability to resolve the dependency.  As it turns out, the restlet version that is needed by the plugin is NOT in maven central.  To fix this, I added a repository to the pom.xml
      (Listing 10)
      
       restlet.org
       restlet.org
       http://maven.restlet.org
       
      Some final thoughts ... for now...
      At this point, you should be able to do a mvn clean install on your command line for the project and open both projects up in Eclipse without eclipse having a heart attack and falling over.  Keep in mind that your mvn clean install will fail, since you haven't yet changed your code to adhere to the new 2.0.1 ways.  This is far as I was able to get to:

      [ERROR] Failed to execute goal org.grails:grails-maven-plugin:2.0.1:clean (default-clean) on project eagle-i-webapp-identity-service: Unable to start Grails: java.lang.reflect.InvocationTargetException: Provider for javax.xml.parsers.SAXParserFactory cannot be found -> [Help 1]
      

      Another thing to mention is be wary of messing around with your maven-ized pom.xml file.  If I remember correctly, you had to issue a specific command to turn the grails project into a maven-ized one and that the command also created/edited the pom.xml file.  One of the motivating factors for us to upgrade is that we have been seeing our CI builds hang for no explicit reason when building this specific project..  Where it hangs varies, but it seems to be hanging while trying to resolve dependencies (another long story, maybe for another time).  I tried to do some "cleverness" by cleaning up what I thought were now obsolete/unused dependencies ... which I should have known better than to do.

      I hope this has been helpful for someone out there.  I tried to document this as best as I could, but it was a long, frustrating process.  I may have missed some steps, if I did and it's causing you issues, please let me know and I'll try to help out.

      Monday, May 23, 2011

      Perl script to "copy" a Rackspace image


      I recently found myself putting together a perl script that performs an rsync of one server in the Rackspace cloud to another server on another account.  Why?  See my next post about restrictions found with Rackspace for details.  Long story short, I needed a way to copy an image from one account to another and Rackspace recommends using rsync.

      Since I will be needing to do this at least once a month for my testing, I thought it best to write up a script using perl that does the rsync.  The first thing was to figure out to successfully do this rsync before putting things together in a script.  I followed the instructions and when I rebooted my new server with the files rsync'ed over, it failed to accept ssh anymore.  On a whim, I decided to go through the basic exclude file from the instructions to see if those directories/files really lived where the file says they would be.

      Ah-ha! That was my problem. I'm not sure which distro was used to create the exclude file, but some of the recommended files/directories to be excluded were located in different places.

      #Suggested by Rackspace
      /etc/hostname
      
      #Actual location on Fedora 14 64bit
      /bin/hostname
       
      
      #Suggested by Rackspace
      /etc/modules 
      
      #Actual location on Fedora 14 64bit
      /etc/sysconfig/modules

      What I did was to do a
      find / -name [sometext]

      Where [sometext] I started from the end of the path and worked my way in to find the location. It was definitely trial and error.  Here is what I have for my final exclude file for Fedora 14 64bit:

      #exclude.txt
      /proc
      /sys
      /tmp
      /dev
      /root/copyImage.log
      /root/.ssh/
      /var/lock
      /etc/fstab
      /etc/mtab
      /etc/resolv.conf
      /usr/share/dbus-1/interfaces
      /etc/networks
      /etc/sysconfig/network
      /etc/sysconfig/network-scripts
      /etc/sysconfig/iptables-config
      /lib/modules/
      /usr/share/selinux/devel/include/kernel
      /bin/hostname
      /usr/lib64/gettext/hostname
      /etc/hosts
      /etc/modprobe*
      /etc/selinux/targeted/modules
      /etc/selinux/targeted/modules/active/modules
      /etc/sysconfig/modules
      /etc/selinux/targeted/modules
      /etc/selinux/targeted/modules/active/modules
      /usr/lib64/gio/modules
      /lib/udev/devices/net
      /usr/lib/ruby/1.8/net
      /etc/init/

      So now that I have a working exclude file, the next thing was to code up a perl script to do this for me.  In order to automate this through the script I needed to be able to:
      • Create an ssh tunnel from the "sending" server to the "receiving" server and be able to generate an ssh key on the "receiving" server.
      • Add the "sending" server's public key to the "receiving" server's authorized_key file
        • In my case, as part of the image, there is an authorized_key file with some public keys in it, which I want available to all servers generated with the image. I added the "sending" server's public key to this file and rsync'ed this file over first
      • Rsync the "sending" server data to the "receiving" server.
      Two of the largest hurdle is:
      1. Open the ssh connection to the "receiving" server
      2. Know when the "receiving" server is asking for the password and supply it
      There are many many perl modules available that do just this in various ways. I didn't think to make a note of which ones I did try, unfortunately.  I ended up using Net::OpenSSH, it had the best documentation and did everything I needed.  I used this in conjunction with Expect module.


      Neither of these modules are included with the Perl package that comes with Fedora 14 64 bit.  In trying to add these modules, I learned some more things.  For example, I learned about CPAN.  This is a little piece of software that manages installation and dependency resolution for perl modules.  Other benefits I found are:
      • Access to modules that may not be in repos yet, i.e. Net::OpenSSH is not available via yum on Fedora 14
      • Type in instmodsh at the command prompt and you can see a list of all installed modules and get information about the modules
        • If module is installed via yum install , will not show up in instmodsh
      Here is a link describing how to install CPAN.  After you follow the instructions at that link, you should also check to see if gcc is installed.  In my case, it was also not included in my default Fedora 14 64bit installation.  It is needed to compile some of the modules (in this case, one of the dependencies for Expect).  The error I got before I installed it is:

      ERROR: cannot run the configured compiler 'gcc'
      (see conf/compilerok.log). Suggestions:
      1) The complier 'gcc' is not in your PATH. Add it
         to the PATH and try again. OR
      2) The compiler isn't installed on your system. Install it. OR
      3) You only have a different compiler installed (e.g. 'gcc').
         Either fix the compiler config in the perl Config.pm
         or install a perl that was built with the right compiler
         (you could build perl yourself with the available compiler).
      
      Note: this is a system-administration issue, please ask your local
      admin for help. Thank you.
      
      Warning: No success on command[/usr/bin/perl Makefile.PL]
      'YAML' not installed, will not store persistent state
        TODDR/IO-Tty-1.10.tar.gz
        /usr/bin/perl Makefile.PL -- NOT OK
      Could not read metadata file. Falling back to other methods to determine prerequisites
      Failed during this command:
       TODDR/IO-Tty-1.10.tar.gz                     : writemakefile NO '/usr/bin/perl Makefile.PL' returned status 6400
      

      Finally, my last hurdle for putting together this script is trouble using the open function in perl.

      #DOES *NOT* WORK
      open(CAT_FILE,"cat /root/test.txt >>/root/test2.txt ") || die "Failed: $!\n";
      
      #DOES WORK
      open(CAT_FILE,"| cat /root/test.txt >>/root/test2.txt ") || die "Failed: $!\n";

      Can you spot the difference?
      So apparently that "|" is required ... oops...guess the documentation was right. *insert chagrin here*.

      So without further ado, please find below my full script to do the rsync step of copying an image to another server on Rackspace:

      Monday, November 1, 2010

      Scala & Json (Lift-web): Trouble with "mapping" field name to another name

      This is a trivial mistake that just ate up the last 2 hours of my life that I will never get back again.

      One thing that is important is to be able to take the "raw" parsed json object and rename some of the fields since GoGrid uses some names that are reserved and/or have other Scala meanings.  For example, GoGrid uses Object and Option to mean things specific to their environment.  

      This is possible by using the JValue's map function to postprocess AST.  Following the example in the readme documenation, I reproduced the following:
      package org.gogrid.sandbox
      abstract class jsonSandbox
      { }
      
      case class Person(firstname: String)
      

      And then started up the Scala interpreter:
      Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Server VM, Java 1.6.0_20).
      Type in expressions to have them evaluated.
      Type :help for more information.
      
      scala> import org.gogrid.sandbox._
      
      scala> import net.liftweb.json.JsonParser._
      import net.liftweb.json.JsonParser._
      
      scala> implicit val formats = net.liftweb.json.DefaultFormats 
      formats: net.liftweb.json.DefaultFormats.type = net.liftweb.json.DefaultFormats$@1c9fe7e
      
      scala> val jsonString = """ { "first-name" : "Jim" } """
      jsonString: java.lang.String =  { "first-name" : "Jim" } 
      
      scala> val json = parse(jsonString)
      json: net.liftweb.json.JsonAST.JValue = JObject(List(JField(first-name,JString(Jim))))
      
      scala> json map {
           | case JField("first-name", x) => JField("firstname", x)
           | case x => x
           | }
      <console>:16: error: not found: value JField
             case JField("first-name", x) => JField("firstname", x)
                  ^
      

      Heh? Why is JField not found???

      My "Oh DUH moment":

      I did NOT import the package where things like JField, JArray are defined.
       
      Insert wall bash here.
      scala> import net.liftweb.json.JsonAST._
      import net.liftweb.json.JsonAST._
      
      scala> json map {
           | case JField("first-name", x) => JField("firstname", x)
           | case x => x
           | }
      res4: net.liftweb.json.JsonAST.JValue = JObject(List(JField(firstname,JString(Jim))))
      

      Dang it.

      Monday, October 25, 2010

      Scala, Jax-RS, and GoGrid: Trouble with annotations


      At the moment, I am trying to create a scala client that talks to GoGrid using their REST-like API.  I am using Apache's Jax-RS implementation.  There are examples (here and here) available online on how to use the Apache implementation to create a Java client and I have been trying to adapt these examples to Scala.

      One annoyance I have encountered so far is how to convert:
      @Path("/myResource")
      @Produces("text/plain")
      public class SomeResource {
          @GET
          public String doGetAsPlainText() {
              ...
          }
      }
      

      My first pass at this is:
      import javax.ws.rs.{ Path, GET, Produces }
      
      @Path("grid/server/list")
      @Produces("text/plain")
      class ListRequest {
          @GET
          var plainText : String = _
      }
      

      Which produces an obscure error (or at least obscure to me):
      Error: "annotation argument needs to be a constant; found: "text/plain" {<error>}
      After trying a variety of things to make this acceptable for Scala and a lot of time searching to no avail, I randomly came across this post, where the author is trying to do something similar and found out that the code needs to look like this:
      import javax.ws.rs.{ Path, GET, Produces }
      
      @Path("grid/server/list")
      @Produces(Array("text/plain"))
      class ListRequest {
          @GET
          var plainText : String = _
      }
      

      Note that "text/plain" is now an element of an array...so apparently when the error says that the argument needs to be a constant...it meant it needs to be in an Array.  Okay...