OpsWorks war deployment failure from S3 - aws-opsworks

I have a war file,. myapp.war (it happens to be a grails app, but this is not material)
I upload this to an s3 bucket, say myapp in us-west-2
I set up an OpsWorks using the S3 repository type:
Repository Type: S3
Repository URL: https://myapp.s3-us-west-2.amazonaws.com/myapp.war
Access key ID: A key with read permission on the above bucket
Secret access key: the secret for this key
Deploy to an instance in Java layer (Tomcat 7)
All lights are green, deployments succeeded
But the app isn't actually deployed
Shelling in to the instance and looking in /usr/share/tomcat7/webapps I find a directory called 'myapp'. Inside this directory is a file called 'archive'. 'archive' appears to be a war file, but it is not named 'archive.war', and it is in a subdirectory of webapps, so tomcat isn't going to deploy it anyway.
Now, the OpsWorks docs say the archive should be a 'zip' file. But:
zipping up myapp.war into a zip archive 'myapp.war.zip' and changing the path to this file results in 'myapp' containing 'myapp.war'. No deployment, since tomcat isn't looking for war files in 'webapps/myapp'
Changing the name of 'myapp.war' to 'myapp.zip' and changing the repository path results in 'myapp' containing the single file 'archive' again.
So. Can anyone describe how to properly provide a war file to OpsWorks from S3?

It appears that the problem has to do with how the zip archive is made.
Jars, war, and the like created with the java 'jar' tool do not work. Zip archives created with a zip tool, and then renamed to have a '.war' extension do.
This is explained here: https://forums.aws.amazon.com/thread.jspa?messageID=559582&#559582
Quoting that post's answer:
Our current extract script doesn't correctly identify WAR files. If
you unpack the WAR file and use zip to pack it, it should work until
we update our script.
So the procedure that works is to:
Explode the war made by your development environment (In the case of grails, the war build cleans up the staging directory for the war, so you don't have an exploded war directory laying around to zip up yourself, you have to unzip it first.)
Zip the contents of the directory created by exploding the war using a zip tool (or, if your build tool leaves the exploded war directory there, then just zip it directly)
Optionally, rename the new zip archive to have a '.war' extension.
Resume the procedure from the original question, step 3 -- that is, upload the war to the s3 bucket and
Specify the S3 path to the war file as the repository in the OpsWorks setup.
EDIT:
After answering this, I discovered that Grails can produce an exploded war directory after all.
// BuildConfig.groovy
...
grails.project.war.exploded.dir = "path/to/exploded/war-directory"
grails.war.exploded=true
...
That directory can be zipped or jarred or whatever you want by your builder/deployer.

From this wiki page you see that a WAR file is just a special JAR file. And if you check out what a JAR is here then you see it is just zipped up compiled java code.
This SuperUser question also touches on the .WAR vs .zip business. Basically, a WAR is just a special ZIP. So when you upload a WAR, you are uploading a ZIP.
Make sure it's a WAR file in the S3 bucket.
Provide the entire link to the S3 WAR file. To get this, right-click the WAR file in S3 and select Properties and then copy the link.

Related

Where should I add AppSpec.yml file in CodeDeploy

I am deploying code from Amazon S3 to EC2 instance with codeDeploy.I have configured the the configuration group and application but I am getting this error
The overall deployment failed because too many individual instances failed deployment, too few healthy instances are available for deployment, or some instances in your deployment group are experiencing problems.
When I check the logs I see
"The CodeDeploy agent did not find an AppSpec file within the unpacked revision directory at revision-relative path \\"appspec.yml\\"
What exactly is a appspec.yml file and where should I place it? i am new to AWS so any help would be appreciated.
All the information you need should be present : Amazon documentation Appspec File.
File location
To verify that you have placed your AppSpec file in the root directory
of the application's source content's directory structure
Add an Application Specification File to a Revision for CodeDeploy
Add an AppSpec File for an AWS Lambda Deployment For a deployment to
an AWS Lambda compute platform:
The AppSpec file contains instructions about the Lambda functions to
be deployed and used for deployment validation.
A revision is the same as an AppSpec file.
An AppSpec file can be written using JSON or YAML.
An AppSpec file can be saved as a text file or entered directly into a
console AppSpec editor when creating a deployment. For more
information, see Create an AWS Lambda Compute Platform Deployment
(Console).
To create an AppSpec file:
Copy the JSON or YAML template into a text editor or into the AppSpec
editor in the console.
Modify the template as needed.
Use a JSON or YAML validator to validate your AppSpec file. If you use
the AppSpec editor, the file is validated when you choose Create
deployment.
If you use a text editor, save the file. If you use the AWS CLI to
create your deployment, reference the AppSpec file if it's on your
hard drive or in an Amazon S3 bucket. If you use the console, you must
push your AppSpec file to Amazon S3.
Add an AppSpec File for an EC2/On-Premises Deployment
To add an AppSpec file to a revision:
Copy the template into a text editor.
Modify the template as needed.
Use a YAML validator to check the validity of your AppSpec file.
Save the file as appspec.yml in the root directory of the revision.
Run one of the following commands to verify that you have placed your
AppSpec file in the root directory:
For Linux, macOS, or Unix:
find /path/to/root/directory -name appspec.yml There will be no output
if the AppSpec file is not found there.
For Windows:
dir path\to\root\directory\appspec.yml A File Not Found error will be
displayed if the AppSpec file is not stored there.
Push the revision to Amazon S3 or GitHub.

Accessing a JSON file in tomcat war and reading it

I want to read a json file placed in resources/data/info.json in my webapp. Got to know that need to use Convertor.class.getResourceAsStream("\\WEB-INF\\classes\\data\\Address.json"); where Convertor is my util class for some reason am unable to read the file and i see the InputStream returning null and i see the below exception :
com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
at [Source: UNKNOWN; line: 1, column: 0]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4133)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3988)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3058)
at com.wf.hrca.util.Convertor.unMarshal(Convertor.java:84)
resources is a folder of your source project on your development machine. Tomcat doesn't care about how your source project looks like. And by the way, when you'll deploy the application in production, there won't be any source project on the machine.
All Tomcat cares about is the war file you deploy. Inside this war file, the WEB-INF/classes directory, along with all the jar files under WEB-INF/lib, constitute the classpath of the application.
Convertor.class.getResourceAsStream(), as the javadoc explains (but you really need to read it to know) expects a /-separated path. If the path starts with a /, then the path starts at one of the roots of the classpath (i.e. / refers to WEB-INF/classes, and to the root of each jar file of WEB-INF/lib).
So, find where the json file is located inside the war file. If it's under /WEB-INF/classes/data/info.json, then you should use
Convertor.class.getResourceAsStream("/data/info.json");

External configuration file

I'm working on a spring-mvc project and was wondering if, like grails, I can create an external configuration file in tomcat with the appconfig folder. My project lives in /var/lib/tomcat7/webapps/<app> and was wondering if placing a configuration file in /var/lib/tomcat7/appconfigs/<config.xml> would work? If so, is it like grails and the application searches that location by default, or do I need to specify where that configuration lives? Thanks
What do you mean by "external configuration file"? Would this config file be separate from the war file? Or would it be packaged along with war file?
If packaged along with war file, you can put it under src/main/resources folder and it should be automatically packaged and placed in classpath.
If not packaged with war file, I usually put the configuration parameters under Tomcat's context.xml. Here's the documentation: http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Environment_Entries

File in executable jar cannot be found when running on AWS EC2

I have a .jar file executing on a aws ec2 instance which contains the following code:
List<String> lines = FileUtils.readLines(new File("googlebooks-eng-all-1gram-20120701-k"));
the file exists in projectname/res and also in /projectname directly. I included /res in the build path. Also I see that the file exists inside the jar file at the root if I export the .java file in eclipse.
If I run the jar localy on my pc it works fine. But if I run it on a ec2 instance it says:
java.io.FileNotFoundException: File 'googlebooks-eng-all-1gram-20120701-k' does not exist
How can that be?
On your PC it is reading from the actual file on the filesystem - that is what new File means - a file on the filesystem.
To access a resource in a jar file you need to call getResourceAsStream or something similar instead.

How to copy a license file which is placed with the setup.msi to target directory (setup created with msifactory)

I have created a Setup file i.e. setup.msi , this file contains a website installer
I have a License.xml file that I want to give to my client with the installer (setup.msi).
Before running the setup.msi , client has to make sure that the License.xml file should be in the same directory where setup.msi resist.
I want my setup.msi file to copy the License.xml file to the Destination directory (where website will be installed , this path will be prompted to user for customization)
I am using MSIFactory for creating setup.msi. I am not able to do this. I searched over net but did not get any accurate answer.
I am not familiar with MSIfactory, but in installshield what I would do is, call a batch script to do the copy and pass the target directory as a parameter to it. or use the 'XCopyFile' function to do the copying.

Resources