5

I'd like to deploy to Tomcat programatically remotely, What are my options? I know about /manager/deploy. Is it possible over JMX? Even an MBean not comming with Tomcat is okay.

Edit: It seems that deploying using /manager/deploy doesn't work - if I do POST request with multipart format containing a file, the servlet returns 405 Method not allowed. Also, the 6.0.32 code of the servlet doesn't seem to implement remote deployment - am I wrong? How to do that?

Thanks.

Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277

3 Answers3

5

Since I found this via google as well, i want to share my deployment and undeployment solution for tomcat 7

-) as ondra-zizka pointed out it is as easy as doing a Put request to the correct URL tough the URL has changed under tomcat7 to /manager/text/deploy?path=&update=

<context-do-deploy-to> needs to start with a forward slash e.g: /deployMe

-) you might need to set permissions for accessing manager app add this to TOMCAT_HOME/conf/tomcat-users.xml

note: the tomcat doc warns you not to give the same user access to more than one role

<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<role rolename="manager-jmx"/>
<user username="tomcat" password="s3cret" roles="manager-gui,manager-script,manager-jmx"/>

-) sample code for deploying a web app to an apache tomcat

package deployment;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

public class DeployManager{

    static CredentialsProvider credsProvider = new BasicCredentialsProvider();;

    public static void main(String args[]) throws ClientProtocolException, IOException{
        /*
         * warning only ever AuthScope.ANY while debugging
         * with these settings the tomcat username and pw are added to EVERY request
         */
        credsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials("tomcat", "s3cret"));

//      deploy();
//      undeploy();
    }



    private static void deploy() throws ClientProtocolException, IOException {
        String url = "http://localhost:8080/manager/text/deploy?path=/deployMe&update=true";
        File file = new File ("deployMe.war") ;

        HttpPut req = new HttpPut(url) ;
        MultipartEntityBuilder meb = MultipartEntityBuilder.create();
        meb.addTextBody("fileDescription", "war file to deploy");
        //"application/octect-stream"
        meb.addBinaryBody("attachment", file, ContentType.APPLICATION_OCTET_STREAM, file.getName());

        req.setEntity(meb.build()) ;
        String response = executeRequest (req, credsProvider);

        System.out.println("Response : "+response);
    }

    public static void undeploy() throws ClientProtocolException, IOException{
        String url = "http://localhost:8080/manager/text/undeploy?path=/deployMe";
        HttpGet req = new HttpGet(url) ;
        String response = executeRequest (req, credsProvider);
        System.out.println("Response : "+response);
    } 

    private static String executeRequest(HttpRequestBase requestBase, CredentialsProvider credsProvider) throws ClientProtocolException, IOException {
        CloseableHttpClient client = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
        InputStream responseStream = null;
        String res = null;
        HttpResponse response = client.execute(requestBase) ;
        HttpEntity responseEntity = response.getEntity() ;
        responseStream = responseEntity.getContent() ;

        BufferedReader br = new BufferedReader (new InputStreamReader (responseStream)) ;
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
            sb.append(System.getProperty("line.separator"));
        }
        br.close() ;
        res = sb.toString();

        return res;
    }
}

-) maven dependencies

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.3</version>
</dependency>

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.3</version>
</dependency>

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.3</version>
</dependency>
Community
  • 1
  • 1
systemkern
  • 1,302
  • 11
  • 13
  • Hi @systemkem, I am trying your solution for deploying a WAR file to a remote Tomcat 7 server. However, when I run my code I get a `SocketException: Software caused connection abort: socket write error` and I am not yet sure why. When I use a 3rd party client to do the remote deployment it works fine. This tells me that my Tomcat server's remote management configuration is correct and that my problem must be within the code itself. Any ideas why I might be getting the Exception shown? Cheers, PM. – Going Bananas Oct 07 '14 at 16:15
  • 1
    This link's http://stackoverflow.com/questions/21647337/http-client-4-3-not-sending-credentials accepted answer contains answer to my question. Cheers. – Going Bananas Oct 08 '14 at 10:42
  • Hello @systemkern, do you know how I can also include a context.xml file as config file when using the MultipartEntityBuilder code you have shown? Cheers, PM. – Going Bananas Apr 09 '15 at 09:43
  • Hi @PonderMuse,do you mean a spring config? – systemkern Apr 10 '15 at 10:08
  • Hello @systemkern, I mean the context.xml that you would usually find inside the war itself under META-INF. Basically we would like to pass in a configurable context.xml for use with a WAR upon remote deploying the war instead of having to open up the WAR, edit the context.xml, save/close the WAR and then remote deploy the WAR (which is what we do at the moment). We are happy to carry on doing this but I was just wondering if it was possible to pass in the context.xml as a config file during the remote deploy HTTP PUT operation. – Going Bananas Apr 10 '15 at 10:14
  • Good Morning @PonderMuse, sorry since i built this over a year ago i do not have the related files anymore – systemkern Apr 13 '15 at 10:13
  • Hello @systemkern, thanks for the reply. I can't see anywhere in the Tomcat 7 documentation how this can be done so I am guessing that it is not possible to pass in a context.xml outside of the WAR during a remote deploy. I think it is only possible when the deploy is done locally. – Going Bananas Apr 13 '15 at 11:07
  • very generally speaking you could probably unzip the war locally and add your context file, then zip it again ... you might even be able to do this "while" streaming the upload – systemkern Apr 14 '15 at 12:50
3

I was following old docs. The upload is done by a PUT request at /manager/deploy?path=<context-do-deploy-to>&update=<true|false>

Also there's an Ant task which uses the PUT methods internally.

Tomcat's JMX MBeans do not allow remote deployment.

Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
  • If you are using Maven you can give [Cargo](http://cargo.codehaus.org/) a shot. It also come with an API so you can invoke remote deployment programmatically if you need to. – Benjamin Muschko Apr 08 '11 at 19:02
1

This is a top google result for some reason. the maven tomcat6 plugin is excellent, assuming you have the manager installed.

Rannick
  • 598
  • 5
  • 19