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/
signature.asc
Description: OpenPGP digital signature