Folks,

Beware, the following is extremely ugly Groovy. I've changed the names
to protect the guilty (I think).

Also, the *_SVR and *_URL values are environment values stored centrally
in Jenkins. That way they can be changed easily. They also show up in
the job logs, which means with a little scripting effort I can get a
history of what versions were deployed to what server when.

Please review and laugh . . . or better yet, proffer improvements :-).

On 5/19/2017 10:10 AM, Decker, Richard M wrote:
> Mark,
> 
>> -----Original Message-----
>> From: Mark Eggers [mailto:its_toas...@yahoo.com.INVALID]
>> Sent: Friday, May 19, 2017 10:44 AM
>> To: Tomcat Users List <users@tomcat.apache.org>
>> Subject: Re: Tomcat on macOS
>>
>> Chris,
>>
>> On 5/19/2017 7:33 AM, Christopher Schultz wrote:
>>> Israel,
>>>
>>> On 5/18/17 10:52 AM, Israel Timoteo wrote:
>>>> Any comments from the community for ...
>>>
>>>> 1) What tools is the community using for simultaneous applications
>>>> deployment on several servers, let’s say more than 20?
>>>
>>> I am using neither of these strategies, but...
>>>
>>> a. FarmWebDeployer [1]
>>
>> Doesn't this require a cluster (and therefore multicast)? That becomes
>> challenging in a cloud environment where there's no multicast easily
>> available.
>>
>>> b. Auto-deploy + scp
>>
>> This would be nice with a little scripting.
>>
>>>
>>> Why in the world are you deploying a web application to 20+
>>> macos-based servers? Or do you have a Macos client and 20+
>>> non-macos-based servers?
>>>
>>>> 4) Is JAVA_OPTS required?
>>>
>>> JAVA_OPTS is only required if you require any java opts. Do you
>>> require such options? Usually, when people set JAVA_OPTS they really
>>> want to set CATALINA_OPTS instead.
>>>
>>> Hope that helps,
>>> -chris
>>>
>>> [1]
>>> http://tomcat.apache.org/tomcat-8.0-doc/config/cluster-deployer.html
>>
>> What I do is use Jenkins, Maven, Nexus, and a little Groovy scripting.
>>
>> 1. Maven with the Tomcat Maven Plugin [1]
>>
>> The WAR file is customized (context.xml) based on the target environment.
>>
>> 2. Jenkins
>>
>> The build is run by Jenkins, and the build number (with a little 0 padding 
>> via a
>> Groovy script) is tacked onto the WAR name as app##0000nn.war.
> 
> I don't mean to hijack the thread, but could you expand on this? Could you 
> please provide examples of your Groovy scripts?
> 
>>
>> This allows the parallel deploy feature to be used [2].
>>
>> 3. Nexus
>>
>> This is where all of the base artifacts are stored. Nexus 2 is used currently
>> since Nexus 3 doesn't have the REST API needed to cleanly interact with the
>> Jenkins job via a Groovy script. Maybe I should learn how to write a Nexus
>> plugin to get lists of artifact versions via REST . . .
>>
>> 4. Groovy scripting
>>
>> Groovy is used in Jenkins to do the following:
>>
>> a. Query Nexus to get a list of artifact versions b. Prevent non-production
>> artifacts from landing on production platforms c. Create the final number for
>> parallel deployment
>>
>> To expand this to multiple machines, a set of pipeline jobs could be created.
>>
>> a. Build the customized WAR for the target environment b. Multiple jobs
>> deploy to the servers in the target environment c. Multiple jobs validate the
>> deployment d. Final job sends mail to interested parties with success / 
>> failure
>>
>> I know that's a lot of infrastructure. There are certainly things that could 
>> be
>> done differently. Ant (with Ivy), or gradle could be used for the builds. A
>> different repository manager could be used (other than Nexus). A different
>> CI / CD system could be used (other than Jenkins).
>>
>> Anything that meets at least the following requirements could be strung
>> together.
>>
>> a. Reliable place to get the WAR file you need to deploy b. Reliable build
>> system that can be automated c. Build system that can deploy to Tomcat d.
>> Testing that the deployment actually worked e. Notification
>>
>> The end result is that some authorized person can log into Jenkins, select a
>> version of an application to deploy, deploy it to the target environment,
>> know that it's been successful (or not), and have notifications automatically
>> sent out.
>>
>> [1] http://tomcat.apache.org/maven-plugin.html
>> [2]
>> https://tomcat.apache.org/tomcat-8.0-
>> doc/config/context.html#Parallel_deployment
>>
>> . . . just my (rather lengthy) 2 cents
>> /mde/

// talks to Nexus 2 servers - NOT Nexus 3
// Gets list of versions for a particular groupId and artifactId
// review and use at your own risk
  def prod =
"http://my.nexus.server.com/nexus/service/local/repositories/releases/content";
  def snap =
"http://my.nexus.server.com/nexus/service/local/repositories/snapshots/content";

  def groupId = ARTIFACT_GROUP
  def artifactId = ARTIFACT_ID
  def target = ARTIFACT_TARGET

  def versions = []

  def locationp = prod + "/" + groupId.replaceAll("\\.","/") + "/" +
artifactId
  def locations = snap + "/" + groupId.replaceAll("\\.","/") + "/" +
artifactId

  // get all available SNAPSHOT versions
  try {
          def scontent = new XmlParser().parseText(new 
URL(locations).getText());
          for (contentNode in scontent.data.'content-item') {
                  if (contentNode.leaf.text() != "true") {
                          versions.add(contentNode.text.text())
                  }
          }
  } catch (FileNotFoundException e) {
  }

  // get all available released versions
  try {
          def pcontent = new XmlParser().parseText(new 
URL(locationp).getText());
          for (contentNode in pcontent.data.'content-item') {
                  if (contentNode.leaf.text() != "true") {
                          versions.add(contentNode.text.text())
                  }
          }
  } catch (FileNotFoundException e) {
  }

  // no artifacts in Nexus repository
  if ( versions.isEmpty() ) {
          versions.add("NO-VERSION")
          return versions
  }

  switch (target) {
          // production servers cannot host SNAPSHOT releases
          case ["PROD","PROD02","PROD01","PROD03","PROD04","PROD05"]:
                  def pversions = []
              for (version in versions) {
                  if (!version.endsWith("SNAPSHOT")) {
                          pversions.add(version)
                  }
              }
              versions = pversions
              // no releases in Nexus repository
              if (versions.isEmpty()) {
                  versions.add("NO-VERSION")
              }
          break
          default:
          break
  }

  sversions = versions.sort().reverse()
  return sversions

// takes artifact versions and creates appropriate Maven parameters
// popcorn needed - scotch recommended - review and use at your own risk
def tname = ''
def url = ''
def svr = ''
def bn = ''
def host = ''
def vurl = ''
def ddate = new Date()

// target server
if (binding.variables.containsKey('ARTIFACT_TARGET')) {
    tname = binding.variables.get('ARTIFACT_TARGET')
    switch (tname) {
        // production - prod01.server.com
        case "PROD01":
                if (binding.variables.containsKey('PROD01_URL')) {
                        url = binding.variables.get('PROD01_URL')
                        host = url - ~/:\d{4}\/manager\/text/
                        vurl ="https://prod01.server.com"; + '/' +
binding.variables.get('ARTIFACT_ID')
                }
                if (binding.variables.containsKey('PROD01_SVR')) {
                        svr = binding.variables.get('PROD01_SVR')
                }
        break
        // production - prod02.server.com
        case "PROD02":
                if (binding.variables.containsKey('PROD02_URL')) {
                        url = binding.variables.get('PROD02_URL')
                        host = url - ~/:\d{4}\/manager\/text/
                        vurl = "http://prod02.server.com"; + '/' +
binding.variables.get('ARTIFACT_ID')
                }
                if (binding.variables.containsKey('PROD02_SVR')) {
                        svr = binding.variables.get('PROD02_SVR')
                }
        break
        // production - PROD03.server.com
        case "PROD03":
                if (binding.variables.containsKey('PROD03_URL')) {
                        url = binding.variables.get('PROD03_URL')
                        host = url - ~/:\d{4}\/manager\/text/
                        vurl = "http://prod03.server.com"; + '/' +
binding.variables.get('ARTIFACT_ID')
                }
                if (binding.variables.containsKey('PROD03_SVR')) {
                        svr = binding.variables.get('PROD03_SVR')
                }
        break
        // production - prod04.server.com
        case "PROD04":
                if (binding.variables.containsKey('PROD04_URL')) {
                        url = binding.variables.get('PROD04_URL')
                        host = url - ~/:\d{4}\/manager\/text/
                        vurl = "prod04.server.com" + '/' +
binding.variables.get('ARTIFACT_ID')
                }
                if (binding.variables.containsKey('PROD04_SVR')) {
                        svr = binding.variables.get('PROD04_SVR')
                }
        break
        // production - prod05.server.com
        case "PROD05":
                if (binding.variables.containsKey('PROD05_URL')) {
                        url = binding.variables.get('PROD05_URL')
                        host = url - ~/:\d{4}\/manager\/text/
                        vurl = "http://prod05.server.com"; + '/' +
binding.variables.get('ARTIFACT_ID')
                }
                if (binding.variables.containsKey('PROD05_SVR')) {
                        svr = binding.variables.get('PROD05_SVR')
                }
        break
        // user acceptance test - uattest.server.com
        case "UATTEST":
                if (binding.variables.containsKey('UATTEST_URL')) {
                        url = binding.variables.get('UATTEST_URL')
                        host = url - ~/:\d{4}\/manager\/text/
                        vurl = "http://uattest.server.com"; + '/' +
binding.variables.get('ARTIFACT_ID')
                }
                if (binding.variables.containsKey('UATTEST_SVR')) {
                        svr = binding.variables.get('UATTEST_SVR')
                }
        break
        // internal test - itest.server.com
        case "ITEST":
                if (binding.variables.containsKey('ITEST_URL')) {
                        url = binding.variables.get('ITEST_URL')
                        host = url - ~/:\d{4}\/manager\/text/
                        vurl = host + '/' + binding.variables.get('ARTIFACT_ID')
                }
                if (binding.variables.containsKey('ITEST_SVR')) {
                        svr = binding.variables.get('ITEST_SVR')
                }
        break
        // default is to deploy to internal test
        default:
                if (binding.variables.containsKey('ITEST_URL')) {
                        url = binding.variables.get('ITEST_URL')
                        host = url - ~/:\d{4}\/manager\/text/
                        vurl = host + '/' + binding.variables.get('ARTIFACT_ID')
                }
                if (binding.variables.containsKey('ITEST_SVR')) {
                        svr = binding.variables.get('ITEST_SVR')
                }
        break
    }
}

// build number with proper zero padding
if (binding.variables.containsKey('BUILD_NUMBER')) {
    bns = binding.variables.get('BUILD_NUMBER')
    bni = bns.toInteger()
    if (bni < 10) {
        bn = '0000' + bni.toString()
    } else if (bni < 100) {
        bn = '000' + bni.toString()
    } else if (bni < 1000) {
        bn = '00' + bni.toString()
    } else if (bni < 10000) {
        bn = '0' + bni.toString()
    } else {
        bn = bn.toString()
    }
} else {
    bn = '00001'
}

return [ TARGET_URL:url, TARGET_SERVER:svr, BN:bn, ARTIFACT_URL:vurl,
DEPLOY_DATE:ddate ]

The second script creates appropriate environment variables for the
following Maven command:

mvn -U clean package tomcat7:deploy -Dbuild.number=${BN}
-Dversion.number=${ARTIFACT_VERSION} -Ddeploy.url=${TARGET_URL}
-Ddeploy.server=${TARGET_SERVER}

The DEPLOY_DATE is used in the email notification, as is the BUILD_USER
Jenkins variable. That way, everyone knows who did bad things to a
server when.

Sorry for the line wrap.

. . . just my (ugly scripting) two cents
/mde/

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to