Search code examples
javaamazon-web-servicesspring-bootubuntuaws-ssm

Systemd Service Unit Unable to Access Jarfile in Ubuntu When Running SSM Document


I am working on a project where I need to install the Spring Boot application Pet Clinic onto an Ubuntu 22 server using SSM Documents. I have attached the Systems Manager Run Document. The error below comes from the command sudo journalctl -u spring-petclinic.service. I tried giving any and all access, running as root, and it still isn't working.

Any idea on how to get this application to stay running?

May 17 21:52:36 ip-10-0-4-141 systemd[1]: spring-petclinic.service: Failed with result 'exit-code'.
May 17 21:52:36 ip-10-0-4-141 systemd[1]: spring-petclinic.service: Scheduled restart job, restart counter is at 3.
May 17 21:52:36 ip-10-0-4-141 systemd[1]: Stopped Spring PetClinic Application.
May 17 21:52:36 ip-10-0-4-141 systemd[1]: Started Spring PetClinic Application.
May 17 21:52:36 ip-10-0-4-141 java[7076]: Error: Unable to access jarfile /clinic/spring-petclinic/target/*.jar
May 17 21:52:36 ip-10-0-4-141 systemd[1]: spring-petclinic.service: Main process exited, code=exited, status=1/FAILURE
May 17 21:52:36 ip-10-0-4-141 systemd[1]: spring-petclinic.service: Failed with result 'exit-code'.
May 17 21:52:36 ip-10-0-4-141 systemd[1]: spring-petclinic.service: Scheduled restart job, restart counter is at 4.
May 17 21:52:36 ip-10-0-4-141 systemd[1]: Stopped Spring PetClinic Application.
May 17 21:52:36 ip-10-0-4-141 systemd[1]: Started Spring PetClinic Application.
May 17 21:52:36 ip-10-0-4-141 java[7077]: Error: Unable to access jarfile /clinic/spring-petclinic/target/*.jar
May 17 21:52:36 ip-10-0-4-141 systemd[1]: spring-petclinic.service: Main process exited, code=exited, status=1/FA
---
schemaVersion: '2.2'
description: Install Java 17 and run the Spring PetClinic application
parameters: {}
mainSteps:
- name: InstallJava17
  action: aws:runShellScript
  inputs:
    runCommand:
    - |
      #!/bin/bash
      
      # Check if Java is installed
      if java -version > /dev/null 2>&1; then
        echo "Java is installed. No need to restart"
      else
        echo "Java is not installed. Restarting after install...."
        # Update package lists
        sudo apt-get update
        
        # Install OpenJDK 17
        sudo apt-get install -y openjdk-17-jdk
          
        # Verify Java installation
        java -version

        exit 194
      fi
      
- name: DownloadApplication
  action: aws:runShellScript
  inputs:
    runCommand:
    - |
      #!/bin/bash
      
      # clean the environment file
      cat /dev/null > /etc/environment
      
      # set the full path
      echo "PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:\$JAVA_HOME/bin\"" | sudo tee -a /etc/environment
      
      # grab the java home and set it in the environment
      JAVA_HOME=$(sudo update-alternatives --config java | grep -o -E '/usr/lib/jvm/[a-zA-Z0-9-]+') 
      echo "JAVA_HOME=\"$JAVA_HOME\"" | sudo tee -a /etc/environment
      
      # update the variables
      source /etc/environment
        
      echo "whoami?"
      sudo whoami
      
      # Create and move into new folder
      sudo mkdir /clinic
      cd /clinic
      
      # Download the repository
      echo "# Download the repository"
      sudo git clone https://github.com/spring-projects/spring-petclinic.git
      
      # Move into the folder
      echo "# Move into the folder"
      cd spring-petclinic
      
      # Start the Maven build
      echo "# Start the Maven build"
      ./mvnw package
      
- name: CreateSystemdService
  action: aws:runShellScript
  inputs:
    runCommand:
    - |
      #!/bin/bash
      
      # clean the environment file
      cat /dev/null > /etc/environment
      
      # set the full path
      echo "PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:\$JAVA_HOME/bin\"" | sudo tee -a /etc/environment
      
      # grab the java home and set it in the environment
      JAVA_HOME=$(sudo update-alternatives --config java | grep -o -E '/usr/lib/jvm/[a-zA-Z0-9-]+') 
      echo "JAVA_HOME=\"$JAVA_HOME\"" | sudo tee -a /etc/environment
      
      # update the variables
      source /etc/environment
      
      # Create systemd service unit
      echo "# Create systemd service unit"
      sudo tee /etc/systemd/system/spring-petclinic.service <<EOF
      [Unit]
      Description=Spring PetClinic Application
      After=network.target
      
      echo "THIS IS THE PATH"
      echo $PATH
      
      echo "THIS IS THE JAVA_HOME"
      echo $JAVA_HOME
      
      [Service]
      ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar /clinic/spring-petclinic/target/*.jar
      Restart=always
      User=root
      
      [Install]
      WantedBy=multi-user.target
      EOF
      
      echo "whoami?"
      sudo whoami
      
      # Reload systemd and start the service
      echo "# Reload systemd and start the service"
      
      echo "whoami?"
      sudo whoami

      echo "daemon is reloading"
      sudo systemctl daemon-reload
      
      echo "whoami?"
      sudo whoami
      
      echo "enabling spring-petclinic"
      sudo systemctl enable spring-petclinic
      
      echo "whoami?"
      sudo whoami
      
      echo "starting spring-petclinic"
      sudo systemctl start spring-petclinic

Solution

  • I think the problems are in this line:

    ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java 
              -jar /clinic/spring-petclinic/target/*.jar
    

    (I have split it for readability.)

    Lets start with:

    java -jar /clinic/spring-petclinic/target/*.jar
    

    The -jar option requires one JAR file. But on the face of it, the * could expand to pathnames for multiple JARs. That doesn't work. The second and subsequent JARs would be passed as command line arguments; i.e. in the "arg list". And they wouldn't be on the classpath.

    Furthermore, if your application does consist of multiple JAR files, the -jar option is not the correct way to run it. Instead, you need to specify a classpath (e.g. using a -cp argument) and give the entrypoint classname. It would looks something like this:

    java -cp /somepath/part1.jar:/somepath/part2.jar com.example.FooCommand ...
    

    (It is also possible to use wildcards in the classpath, but there is a java specific syntax for doing that. Check the java command manual entry for your version of Java.)


    But the actual explanation is simpler than that. The file you have there is a systemd unit configuration file; see https://www.freedesktop.org/software/systemd/man/255/systemd.service.html. The manual entry explains that an ExecStart string is NOT full shell syntax. Some aspects of shell syntax are supported, but * wildcards are NOT supported. (Refer to the systemd.service manual entry for details.)

    Therefore ... the ExecStart you have specified is specifying a JAR file with a literal * character in its pathname. Apparently, it doesn't exist; the java command error message is telling you that.