From 2437ce4f802f1b6f6debf7448c9ab6053398b475 Mon Sep 17 00:00:00 2001 From: Ben Hale Date: Tue, 31 Mar 2020 12:30:32 -0700 Subject: [PATCH] Implementation This change contributes an implementation that installs an Apache Tomcat instance and a collection of configuration and extensions to optimize for running in a container. It also allows users to contribute external configuration via a URI. Signed-off-by: Ben Hale --- README.md | 39 ++- buildpack.toml | 2 +- cmd/build/main.go | 9 + cmd/detect/main.go | 6 + go.mod | 10 + go.sum | 94 ++++++ tomcat/access-logging-support.sh | 7 + tomcat/base.go | 307 ++++++++++++++++++ tomcat/base_test.go | 230 +++++++++++++ tomcat/build.go | 132 ++++++++ tomcat/build_test.go | 216 ++++++++++++ tomcat/detect.go | 50 +++ tomcat/detect_test.go | 83 +++++ tomcat/home.go | 56 ++++ tomcat/home_test.go | 68 ++++ tomcat/init_test.go | 33 ++ tomcat/setenv.sh | 2 + tomcat/statik/statik.go | 14 + ...ecf4a199a5821c5b8b1dcd11a67666c1e2cd6.toml | 2 + ...ternal-configuration-with-directory.tar.gz | Bin 0 -> 168 bytes ...503d8288d50df519ff4db7cca0ff9fe83c324.toml | 2 + .../stub-external-configuration.tar.gz | Bin 0 -> 133 bytes ...1fbb78cf3040e313a82c06696f5058e190534.toml | 2 + .../stub-tomcat-lifecycle-support.jar | Bin 0 -> 437 bytes ...c7b08f8de0e638cb0936abcaa2316e7460c1e.toml | 2 + .../stub-tomcat.tar.gz | Bin 0 -> 177 bytes ...2d0e6a963de7313350e306d470e44e330a5d2.toml | 2 + .../stub-tomcat-access-logging-support.jar | Bin 0 -> 437 bytes ...7c6b505090b7484c2ba9be846334e31c44a2c.toml | 2 + .../stub-tomcat-logging-support.jar | Bin 0 -> 437 bytes 30 files changed, 1366 insertions(+), 4 deletions(-) create mode 100644 go.sum create mode 100644 tomcat/access-logging-support.sh create mode 100644 tomcat/base.go create mode 100644 tomcat/base_test.go create mode 100644 tomcat/build.go create mode 100644 tomcat/build_test.go create mode 100644 tomcat/detect.go create mode 100644 tomcat/detect_test.go create mode 100644 tomcat/home.go create mode 100644 tomcat/home_test.go create mode 100644 tomcat/init_test.go create mode 100644 tomcat/setenv.sh create mode 100644 tomcat/statik/statik.go create mode 100644 tomcat/testdata/060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6.toml create mode 100644 tomcat/testdata/060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6/stub-external-configuration-with-directory.tar.gz create mode 100644 tomcat/testdata/22e708cfd301430cbcf8d1c2289503d8288d50df519ff4db7cca0ff9fe83c324.toml create mode 100644 tomcat/testdata/22e708cfd301430cbcf8d1c2289503d8288d50df519ff4db7cca0ff9fe83c324/stub-external-configuration.tar.gz create mode 100644 tomcat/testdata/723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534.toml create mode 100644 tomcat/testdata/723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534/stub-tomcat-lifecycle-support.jar create mode 100644 tomcat/testdata/c31f9fd9b9458dd8dda54ce879dc7b08f8de0e638cb0936abcaa2316e7460c1e.toml create mode 100644 tomcat/testdata/c31f9fd9b9458dd8dda54ce879dc7b08f8de0e638cb0936abcaa2316e7460c1e/stub-tomcat.tar.gz create mode 100644 tomcat/testdata/d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2.toml create mode 100644 tomcat/testdata/d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2/stub-tomcat-access-logging-support.jar create mode 100644 tomcat/testdata/e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c.toml create mode 100644 tomcat/testdata/e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c/stub-tomcat-logging-support.jar diff --git a/README.md b/README.md index a072c7c..792ad9f 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,46 @@ The Paketo Apache Tomcat Buildpack is a Cloud Native Buildpack that contributes Apache Tomcat and Process Types for WARs. ## Behavior -This buildpack will participate any of the following conditions are met +This buildpack will participate all of the following conditions are met -* +* `/WEB-INF` exists The buildpack will do the following: -* +* Requests that a JRE be installed +* Contribute a Tomcat instance to `$CATALINA_HOME` +* Contribute a Tomcat instance to `$CATALINA_BASE` + * Contribute `context.xml`, `logging.properties`, `server.xml`, and `web.xml` to `conf/` + * Contribute [Access Logging Support][als], [Lifecycle Support][lcs], and [Logging Support][lgs] + * Contribute external configuration if available +* Contributes `tomcat`, `task`, and `web` process types + +[als]: https://github.com/cloudfoundry/java-buildpack-support/tree/master/tomcat-access-logging-support +[lcs]: https://github.com/cloudfoundry/java-buildpack-support/tree/master/tomcat-lifecycle-support +[lgs]: https://github.com/cloudfoundry/java-buildpack-support/tree/master/tomcat-logging-support + +## Configuration +| Environment Variable | Description +| -------------------- | ----------- +| `$BP_TOMCAT_CONTEXT_PATH` | The context path to mount the application at. Defaults to empty (`ROOT`). +| `$BP_TOMCAT_EXT_CONF_SHA256` | The SHA256 hash of the external configuration package +| `$BP_TOMCAT_EXT_CONF_STRIP` | The number of directory levels to strip from the external configuration package. Defaults to `0`. +| `$BP_TOMCAT_EXT_CONF_URI` | The download URI of the external configuration package +| `$BP_TOMCAT_EXT_CONF_VERSION` | The version of the external configuration package +| `$BP_TOMCAT_VERSION` | Configure a specific Tomcat version. This value must _exactly_ match a version available in the buildpack so typically it would configured to a wildcard such as `9.*`. +| `BPL_TOMCAT_ACCESS_LOGGING` | Whether access logging should be activated. Defaults to inactive. + +### External Configuration Package +The artifacts that the repository provides must be in TAR format and must follow the Tomcat archive structure: + +``` + +└── conf + ├── context.xml + ├── server.xml + ├── web.xml + ├── ... +``` ## License This buildpack is released under version 2.0 of the [Apache License][a]. diff --git a/buildpack.toml b/buildpack.toml index 0cefa9b..1b2dc79 100644 --- a/buildpack.toml +++ b/buildpack.toml @@ -17,7 +17,7 @@ api = "0.2" [buildpack] id = "paketo-buildpacks/apache-tomcat" name = "Paketo Apache Tomcat Buildpack" -version = "{{.Version}}" +version = "{{.version}}" [[stacks]] id = "io.buildpacks.stacks.bionic" diff --git a/cmd/build/main.go b/cmd/build/main.go index 3d2908d..53ce448 100644 --- a/cmd/build/main.go +++ b/cmd/build/main.go @@ -16,5 +16,14 @@ package main +import ( + "os" + + "github.com/paketo-buildpacks/apache-tomcat/tomcat" + "github.com/paketo-buildpacks/libpak" + "github.com/paketo-buildpacks/libpak/bard" +) + func main() { + libpak.Build(tomcat.Build{Logger: bard.NewLogger(os.Stdout)}) } diff --git a/cmd/detect/main.go b/cmd/detect/main.go index 3d2908d..9f585a6 100644 --- a/cmd/detect/main.go +++ b/cmd/detect/main.go @@ -16,5 +16,11 @@ package main +import ( + "github.com/paketo-buildpacks/apache-tomcat/tomcat" + "github.com/paketo-buildpacks/libpak" +) + func main() { + libpak.Detect(tomcat.Detect{}) } diff --git a/go.mod b/go.mod index 9a35095..fea201c 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,13 @@ module github.com/paketo-buildpacks/apache-tomcat go 1.14 + +require ( + github.com/buildpacks/libcnb v1.6.0 + github.com/heroku/color v0.0.6 + github.com/onsi/gomega v1.9.0 + github.com/paketo-buildpacks/libpak v1.21.0 + github.com/rakyll/statik v0.1.7 + github.com/sclevine/spec v1.4.0 + golang.org/x/sys v0.0.0-20200331124033-c3d80250170d // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5fe2ab2 --- /dev/null +++ b/go.sum @@ -0,0 +1,94 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14= +github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/buildpacks/libcnb v1.6.0 h1:emdOidXjU2nnAy4qT+VbjGQdqYZ3M/9BERdIZOlBLYM= +github.com/buildpacks/libcnb v1.6.0/go.mod h1:heL8ONtmWudtDiTJsV6XgCszCUT2LC0t972PLnPQ4aE= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/heroku/color v0.0.6 h1:UTFFMrmMLFcL3OweqP1lAdp8i1y/9oHqkeHjQ/b/Ny0= +github.com/heroku/color v0.0.6/go.mod h1:ZBvOcx7cTF2QKOv4LbmoBtNl5uB17qWxGuzZrsi1wLU= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= +github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/paketo-buildpacks/libpak v1.21.0 h1:a81FtNkTaTcCiQ47mkPRU8TEJBT2sGY42sEyA7PVdIE= +github.com/paketo-buildpacks/libpak v1.21.0/go.mod h1:5J6ne6iASiZPI0oBnZ1hB9G7GTMREf5+2WAFmawFWEg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= +github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= +github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= +github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE= +golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/tomcat/access-logging-support.sh b/tomcat/access-logging-support.sh new file mode 100644 index 0000000..71d9bfe --- /dev/null +++ b/tomcat/access-logging-support.sh @@ -0,0 +1,7 @@ +ENABLED=${BPL_TOMCAT_ACCESS_LOGGING:=n} + +[[ "${ENABLED}" = "n" ]] && return + +printf "Tomcat Access Logging enabled\n" + +export JAVA_OPTS="${JAVA_OPTS} -Daccess.logging.enabled=true" diff --git a/tomcat/base.go b/tomcat/base.go new file mode 100644 index 0000000..de2a1ac --- /dev/null +++ b/tomcat/base.go @@ -0,0 +1,307 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tomcat + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + + "github.com/buildpacks/libcnb" + "github.com/heroku/color" + _ "github.com/paketo-buildpacks/apache-tomcat/tomcat/statik" + "github.com/paketo-buildpacks/libpak" + "github.com/paketo-buildpacks/libpak/bard" + "github.com/paketo-buildpacks/libpak/crush" + "github.com/paketo-buildpacks/libpak/sherpa" +) + +type Base struct { + AccessLoggingDependency libpak.BuildpackDependency + ApplicationPath string + BuildpackPath string + ContextPath string + DependencyCache libpak.DependencyCache + ExternalConfigurationDependency *libpak.BuildpackDependency + LayerContributor libpak.LayerContributor + LifecycleDependency libpak.BuildpackDependency + LoggingDependency libpak.BuildpackDependency + Logger bard.Logger +} + +type Metadata struct { + ContextPath string `mapstructure:"context-path"` + Dependencies []libpak.BuildpackDependency `mapstructure:"dependencies"` +} + +func NewBase(applicationPath string, buildpackPath string, contextPath string, + accessLoggingDependency libpak.BuildpackDependency, externalConfigurationDependency *libpak.BuildpackDependency, + lifecycleDependency libpak.BuildpackDependency, loggingDependency libpak.BuildpackDependency, + cache libpak.DependencyCache, plan *libcnb.BuildpackPlan) Base { + + expected := Metadata{ + ContextPath: contextPath, + Dependencies: []libpak.BuildpackDependency{ + accessLoggingDependency, + lifecycleDependency, + loggingDependency, + }, + } + + plan.Entries = append(plan.Entries, accessLoggingDependency.AsBuildpackPlanEntry()) + plan.Entries = append(plan.Entries, lifecycleDependency.AsBuildpackPlanEntry()) + plan.Entries = append(plan.Entries, loggingDependency.AsBuildpackPlanEntry()) + + if externalConfigurationDependency != nil { + expected.Dependencies = append(expected.Dependencies, *externalConfigurationDependency) + + plan.Entries = append(plan.Entries, externalConfigurationDependency.AsBuildpackPlanEntry()) + } + + b := Base{ + AccessLoggingDependency: accessLoggingDependency, + ApplicationPath: applicationPath, + BuildpackPath: buildpackPath, + ContextPath: contextPath, + DependencyCache: cache, + ExternalConfigurationDependency: externalConfigurationDependency, + LayerContributor: libpak.NewLayerContributor("Apache Tomcat Support", expected), + LifecycleDependency: lifecycleDependency, + LoggingDependency: loggingDependency, + } + + return b +} + +//go:generate statik -src . -include *.sh + +func (b Base) Contribute(layer libcnb.Layer) (libcnb.Layer, error) { + b.LayerContributor.Logger = b.Logger + + return b.LayerContributor.Contribute(layer, func() (libcnb.Layer, error) { + if err := b.ContributeConfiguration(layer); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to contribute configuration\n%w", err) + } + + if err := b.ContributeAccessLogging(layer); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to contribute access logging\n%w", err) + } + + if err := b.ContributeLifecycle(layer); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to contribute lifecycle\n%w", err) + } + + if err := b.ContributeLogging(layer); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to contribute logging\n%w", err) + } + + if b.ExternalConfigurationDependency != nil { + if err := b.ContributeExternalConfiguration(layer); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to contribute external configuration\n%w", err) + } + } + + file := filepath.Join(layer.Path, "temp") + if err := os.MkdirAll(file, 0700); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to create directory %s\n%w", file, err) + } + + file = filepath.Join(layer.Path, "webapps") + if err := os.MkdirAll(file, 0755); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to create directory %s\n%w", file, err) + } + + file = filepath.Join(layer.Path, "webapps", b.ContextPath) + b.Logger.Headerf("Mounting application at %s", b.ContextPath) + if err := os.Symlink(b.ApplicationPath, file); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to create symlink from %s to %s\n%w", b.ApplicationPath, file, err) + } + + layer.LaunchEnvironment.Override("CATALINA_BASE", layer.Path) + + layer.Launch = true + return layer, nil + }) +} + +func (b Base) ContributeAccessLogging(layer libcnb.Layer) error { + b.Logger.Header(color.BlueString("%s %s", b.AccessLoggingDependency.Name, b.AccessLoggingDependency.Version)) + + artifact, err := b.DependencyCache.Artifact(b.AccessLoggingDependency) + if err != nil { + return fmt.Errorf("unable to get dependency %s\n%w", b.AccessLoggingDependency.ID, err) + } + defer artifact.Close() + + b.Logger.Bodyf("Copying to %s/lib", layer.Path) + + file := filepath.Join(layer.Path, "lib", filepath.Base(artifact.Name())) + if err := sherpa.CopyFile(artifact, file); err != nil { + return fmt.Errorf("unable to copy %s to %s\n%w", artifact.Name(), file, err) + } + + s, err := sherpa.StaticFile("/access-logging-support.sh") + if err != nil { + return fmt.Errorf("unable to load access-logging-support.sh\n%w", err) + } + + layer.Profile.Add("access-logging-support.sh", s) + + return nil +} + +func (b Base) ContributeConfiguration(layer libcnb.Layer) error { + file := filepath.Join(layer.Path, "conf") + if err := os.MkdirAll(file, 0755); err != nil { + return fmt.Errorf("unable to create directory %s\n%w", file, err) + } + + b.Logger.Bodyf("Copying context.xml to %s/conf", layer.Path) + file = filepath.Join(b.BuildpackPath, "resources", "context.xml") + in, err := os.Open(file) + if err != nil { + return fmt.Errorf("unable to open %s\n%w", file, err) + } + defer in.Close() + + file = filepath.Join(layer.Path, "conf", "context.xml") + if err := sherpa.CopyFile(in, file); err != nil { + return fmt.Errorf("unable to copy %s to %s\n%w", in.Name(), file, err) + } + + b.Logger.Bodyf("Copying logging.properties to %s/conf", layer.Path) + file = filepath.Join(b.BuildpackPath, "resources", "logging.properties") + in, err = os.Open(file) + if err != nil { + return fmt.Errorf("unable to open %s\n%w", file, err) + } + defer in.Close() + + file = filepath.Join(layer.Path, "conf", "logging.properties") + if err := sherpa.CopyFile(in, file); err != nil { + return fmt.Errorf("unable to copy %s to %s\n%w", in.Name(), file, err) + } + + b.Logger.Bodyf("Copying server.xml to %s/conf", layer.Path) + file = filepath.Join(b.BuildpackPath, "resources", "server.xml") + in, err = os.Open(file) + if err != nil { + return fmt.Errorf("unable to open %s\n%w", file, err) + } + defer in.Close() + + file = filepath.Join(layer.Path, "conf", "server.xml") + if err := sherpa.CopyFile(in, file); err != nil { + return fmt.Errorf("unable to copy %s to %s\n%w", in.Name(), file, err) + } + + b.Logger.Bodyf("Copying web.xml to %s/conf", layer.Path) + file = filepath.Join(b.BuildpackPath, "resources", "web.xml") + in, err = os.Open(file) + if err != nil { + return fmt.Errorf("unable to open %s\n%w", file, err) + } + defer in.Close() + + file = filepath.Join(layer.Path, "conf", "web.xml") + if err := sherpa.CopyFile(in, file); err != nil { + return fmt.Errorf("unable to copy %s to %s\n%w", in.Name(), file, err) + } + + return nil +} + +func (b Base) ContributeExternalConfiguration(layer libcnb.Layer) error { + b.Logger.Header(color.BlueString("%s %s", b.ExternalConfigurationDependency.Name, b.ExternalConfigurationDependency.Version)) + + artifact, err := b.DependencyCache.Artifact(*b.ExternalConfigurationDependency) + if err != nil { + return fmt.Errorf("unable to get dependency %s\n%w", b.ExternalConfigurationDependency.ID, err) + } + defer artifact.Close() + + b.Logger.Bodyf("Expanding to %s", layer.Path) + + c := 0 + if s, ok := os.LookupEnv("BP_TOMCAT_EXT_CONF_STRIP"); ok { + if c, err = strconv.Atoi(s); err != nil { + return fmt.Errorf("unable to parse %s to integer\n%w", s, err) + } + } + + if err := crush.ExtractTarGz(artifact, layer.Path, c); err != nil { + return fmt.Errorf("unable to expand external configuration\n%w", err) + } + + return nil +} + +func (b Base) ContributeLifecycle(layer libcnb.Layer) error { + b.Logger.Header(color.BlueString("%s %s", b.LifecycleDependency.Name, b.LifecycleDependency.Version)) + + artifact, err := b.DependencyCache.Artifact(b.LifecycleDependency) + if err != nil { + return fmt.Errorf("unable to get dependency %s\n%w", b.LifecycleDependency.ID, err) + } + defer artifact.Close() + + b.Logger.Bodyf("Copying to %s/lib", layer.Path) + + file := filepath.Join(layer.Path, "lib", filepath.Base(artifact.Name())) + if err := sherpa.CopyFile(artifact, file); err != nil { + return fmt.Errorf("unable to copy %s to %s\n%w", artifact.Name(), file, err) + } + + return nil +} + +func (b Base) ContributeLogging(layer libcnb.Layer) error { + b.Logger.Header(color.BlueString("%s %s", b.LoggingDependency.Name, b.LoggingDependency.Version)) + + artifact, err := b.DependencyCache.Artifact(b.LoggingDependency) + if err != nil { + return fmt.Errorf("unable to get dependency %s\n%w", b.LoggingDependency.ID, err) + } + defer artifact.Close() + + b.Logger.Bodyf("Copying to %s/bin", layer.Path) + + file := filepath.Join(layer.Path, "bin", filepath.Base(artifact.Name())) + if err := sherpa.CopyFile(artifact, file); err != nil { + return fmt.Errorf("unable to copy %s to %s\n%w", artifact.Name(), file, err) + } + + b.Logger.Bodyf("Writing %s/bin/setenv.sh", layer.Path) + + s, err := sherpa.TemplateFile("/setenv.sh", map[string]interface{}{"classpath": file}) + if err != nil { + return fmt.Errorf("unable to load setenv.sh\n%w", err) + } + + file = filepath.Join(layer.Path, "bin", "setenv.sh") + if err = ioutil.WriteFile(file, []byte(s), 0755); err != nil { + return fmt.Errorf("unable to write file %s\n%w", file, err) + } + + return nil +} + +func (Base) Name() string { + return "catalina-base" +} diff --git a/tomcat/base_test.go b/tomcat/base_test.go new file mode 100644 index 0000000..ac8f428 --- /dev/null +++ b/tomcat/base_test.go @@ -0,0 +1,230 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tomcat_test + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/buildpacks/libcnb" + . "github.com/onsi/gomega" + "github.com/paketo-buildpacks/apache-tomcat/tomcat" + "github.com/paketo-buildpacks/libpak" + "github.com/sclevine/spec" +) + +func testBase(t *testing.T, context spec.G, it spec.S) { + var ( + Expect = NewWithT(t).Expect + + ctx libcnb.BuildContext + ) + + it.Before(func() { + var err error + + ctx.Application.Path, err = ioutil.TempDir("", "base-application") + Expect(err).NotTo(HaveOccurred()) + + ctx.Buildpack.Path, err = ioutil.TempDir("", "base-buildpack") + Expect(err).NotTo(HaveOccurred()) + + ctx.Layers.Path, err = ioutil.TempDir("", "base-layers") + Expect(err).NotTo(HaveOccurred()) + }) + + it.After(func() { + Expect(os.RemoveAll(ctx.Application.Path)).To(Succeed()) + Expect(os.RemoveAll(ctx.Buildpack.Path)).To(Succeed()) + Expect(os.RemoveAll(ctx.Layers.Path)).To(Succeed()) + }) + + it("contributes catalina base", func() { + Expect(os.MkdirAll(filepath.Join(ctx.Buildpack.Path, "resources"), 0755)).To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "context.xml"), []byte{}, 0644)). + To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "logging.properties"), []byte{}, 0644)). + To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "server.xml"), []byte{}, 0644)). + To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "web.xml"), []byte{}, 0644)). + To(Succeed()) + + accessLoggingDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat-access-logging-support.jar", + SHA256: "d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2", + } + lifecycleDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat-lifecycle-support.jar", + SHA256: "723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534", + } + loggingDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat-logging-support.jar", + SHA256: "e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c", + } + + dc := libpak.DependencyCache{CachePath: "testdata"} + + plan := libcnb.BuildpackPlan{} + + b := tomcat.NewBase(ctx.Application.Path, ctx.Buildpack.Path, "test-context-path", accessLoggingDep, nil, + lifecycleDep, loggingDep, dc, &plan) + layer, err := ctx.Layers.Layer("test-layer") + Expect(err).NotTo(HaveOccurred()) + + layer, err = b.Contribute(layer) + Expect(err).NotTo(HaveOccurred()) + + Expect(plan.Entries).To(HaveLen(3)) + Expect(plan.Entries[0].Metadata["sha256"]).To(Equal("d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2")) + Expect(plan.Entries[1].Metadata["sha256"]).To(Equal("723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534")) + Expect(plan.Entries[2].Metadata["sha256"]).To(Equal("e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c")) + Expect(layer.Launch).To(BeTrue()) + Expect(filepath.Join(layer.Path, "conf", "context.xml")).To(BeARegularFile()) + Expect(filepath.Join(layer.Path, "conf", "logging.properties")).To(BeARegularFile()) + Expect(filepath.Join(layer.Path, "conf", "server.xml")).To(BeARegularFile()) + Expect(filepath.Join(layer.Path, "conf", "web.xml")).To(BeARegularFile()) + Expect(filepath.Join(layer.Path, "lib", "stub-tomcat-access-logging-support.jar")).To(BeARegularFile()) + Expect(layer.Profile["access-logging-support.sh"]).To(Equal(`ENABLED=${BPL_TOMCAT_ACCESS_LOGGING:=n} + +[[ "${ENABLED}" = "n" ]] && return + +printf "Tomcat Access Logging enabled\n" + +export JAVA_OPTS="${JAVA_OPTS} -Daccess.logging.enabled=true" +`)) + Expect(filepath.Join(layer.Path, "lib", "stub-tomcat-lifecycle-support.jar")).To(BeARegularFile()) + Expect(filepath.Join(layer.Path, "bin", "stub-tomcat-logging-support.jar")).To(BeARegularFile()) + Expect(ioutil.ReadFile(filepath.Join(layer.Path, "bin", "setenv.sh"))).To(Equal([]byte(fmt.Sprintf(`# shellcheck disable=SC2034 +CLASSPATH="%s" +`, filepath.Join(layer.Path, "bin", "stub-tomcat-logging-support.jar"))))) + Expect(layer.LaunchEnvironment["CATALINA_BASE.override"]).To(Equal(layer.Path)) + Expect(filepath.Join(layer.Path, "temp")).To(BeADirectory()) + + file := filepath.Join(layer.Path, "webapps", "test-context-path") + fi, err := os.Lstat(file) + Expect(err).NotTo(HaveOccurred()) + Expect(fi.Mode() & os.ModeSymlink).To(Equal(os.ModeSymlink)) + Expect(os.Readlink(file)).To(Equal(ctx.Application.Path)) + + Expect(layer.LaunchEnvironment["CATALINA_BASE.override"]).To(Equal(layer.Path)) + }) + + it("contributes custom configuration", func() { + Expect(os.MkdirAll(filepath.Join(ctx.Buildpack.Path, "resources"), 0755)).To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "context.xml"), []byte{}, 0644)). + To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "logging.properties"), []byte{}, 0644)). + To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "server.xml"), []byte{}, 0644)). + To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "web.xml"), []byte{}, 0644)). + To(Succeed()) + + accessLoggingDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat-access-logging-support.jar", + SHA256: "d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2", + } + externalConfigurationDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-external-configuration.tar.gz", + SHA256: "22e708cfd301430cbcf8d1c2289503d8288d50df519ff4db7cca0ff9fe83c324", + } + lifecycleDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat-lifecycle-support.jar", + SHA256: "723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534", + } + loggingDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat-logging-support.jar", + SHA256: "e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c", + } + + dc := libpak.DependencyCache{CachePath: "testdata"} + + plan := libcnb.BuildpackPlan{} + + b := tomcat.NewBase(ctx.Application.Path, ctx.Buildpack.Path, "test-context-path", accessLoggingDep, + &externalConfigurationDep, lifecycleDep, loggingDep, dc, &plan) + layer, err := ctx.Layers.Layer("test-layer") + Expect(err).NotTo(HaveOccurred()) + + layer, err = b.Contribute(layer) + Expect(err).NotTo(HaveOccurred()) + + Expect(plan.Entries).To(HaveLen(4)) + Expect(plan.Entries[3].Metadata["sha256"]).To(Equal("22e708cfd301430cbcf8d1c2289503d8288d50df519ff4db7cca0ff9fe83c324")) + Expect(filepath.Join(layer.Path, "fixture-marker")).To(BeARegularFile()) + }) + + context("$BP_TOMCAT_EXT_CONF_STRIP", func() { + it.Before(func() { + Expect(os.Setenv("BP_TOMCAT_EXT_CONF_STRIP", "1")).To(Succeed()) + }) + + it.After(func() { + Expect(os.Unsetenv("BP_TOMCAT_EXT_CONF_STRIP")).To(Succeed()) + }) + + it("contributes custom configuration with directory", func() { + Expect(os.MkdirAll(filepath.Join(ctx.Buildpack.Path, "resources"), 0755)).To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "context.xml"), []byte{}, 0644)). + To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "logging.properties"), []byte{}, 0644)). + To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "server.xml"), []byte{}, 0644)). + To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(ctx.Buildpack.Path, "resources", "web.xml"), []byte{}, 0644)). + To(Succeed()) + + accessLoggingDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat-access-logging-support.jar", + SHA256: "d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2", + } + externalConfigurationDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-external-configuration-with-directory.tar.gz", + SHA256: "060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6", + } + lifecycleDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat-lifecycle-support.jar", + SHA256: "723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534", + } + loggingDep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat-logging-support.jar", + SHA256: "e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c", + } + + dc := libpak.DependencyCache{CachePath: "testdata"} + + plan := libcnb.BuildpackPlan{} + + b := tomcat.NewBase(ctx.Application.Path, ctx.Buildpack.Path, "test-context-path", accessLoggingDep, + &externalConfigurationDep, lifecycleDep, loggingDep, dc, &plan) + layer, err := ctx.Layers.Layer("test-layer") + Expect(err).NotTo(HaveOccurred()) + + layer, err = b.Contribute(layer) + Expect(err).NotTo(HaveOccurred()) + + Expect(plan.Entries).To(HaveLen(4)) + Expect(plan.Entries[3].Metadata["sha256"]).To(Equal("060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6")) + Expect(filepath.Join(layer.Path, "fixture-marker")).To(BeARegularFile()) + }) + }) + +} diff --git a/tomcat/build.go b/tomcat/build.go new file mode 100644 index 0000000..3f0889e --- /dev/null +++ b/tomcat/build.go @@ -0,0 +1,132 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tomcat + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/buildpacks/libcnb" + "github.com/paketo-buildpacks/libpak" + "github.com/paketo-buildpacks/libpak/bard" +) + +type Build struct { + Logger bard.Logger +} + +func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) { + file := filepath.Join(context.Application.Path, "WEB-INF") + if _, err := os.Stat(file); err != nil && !os.IsNotExist(err) { + return libcnb.BuildResult{}, fmt.Errorf("unable to stat file %s\n%w", file, err) + } else if os.IsNotExist(err) { + return libcnb.BuildResult{}, nil + } + + b.Logger.Title(context.Buildpack) + b.Logger.Body(bard.FormatUserConfig("BP_TOMCAT_CONTEXT_PATH", "the application context path", "ROOT")) + b.Logger.Body(bard.FormatUserConfig("BP_TOMCAT_EXT_CONF_SHA256", "the SHA256 hash of the external Tomcat configuration archive", "")) + b.Logger.Body(bard.FormatUserConfig("BP_TOMCAT_EXT_CONF_STRIP", "the number of directory components to strip from the external Tomcat configuration archive", "0")) + b.Logger.Body(bard.FormatUserConfig("BP_TOMCAT_EXT_CONF_URI", "the download external Tomcat configuration location", "")) + b.Logger.Body(bard.FormatUserConfig("BP_TOMCAT_EXT_CONF_VERSION", "the version of the external Tomcat configuration", "")) + b.Logger.Body(bard.FormatUserConfig("BP_TOMCAT_VERSION", "the Tomcat version", "9.*")) + b.Logger.Body(bard.FormatUserConfig("BPL_TOMCAT_ACCESS_LOGGING", "the Tomcat access logging state", "disabled")) + + command := "catalina.sh run" + result := libcnb.BuildResult{ + Processes: []libcnb.Process{ + {Type: "task", Command: command}, + {Type: "tomcat", Command: command}, + {Type: "web", Command: command}, + }, + } + + md, err := libpak.NewBuildpackMetadata(context.Buildpack.Metadata) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to unmarshal buildpack metadata\n%w", err) + } + + dr, err := libpak.NewDependencyResolver(context) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to create dependency resolver\n%w", err) + } + + dc := libpak.NewDependencyCache(context.Buildpack) + dc.Logger = b.Logger + + v := md.DefaultVersions["tomcat"] + if s, ok := os.LookupEnv("BP_TOMCAT_VERSION"); ok { + v = s + } + tomcatDep, err := dr.Resolve("tomcat", v) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to find dependency\n%w", err) + } + + home := NewHome(tomcatDep, dc, &result.Plan) + home.Logger = b.Logger + result.Layers = append(result.Layers, home) + + accessLoggingDependency, err := dr.Resolve("tomcat-access-logging-support", "") + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to find dependency\n%w", err) + } + + lifecycleDependency, err := dr.Resolve("tomcat-lifecycle-support", "") + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to find dependency\n%w", err) + } + + loggingDependency, err := dr.Resolve("tomcat-logging-support", "") + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to find dependency\n%w", err) + } + + var externalConfigurationDependency *libpak.BuildpackDependency + if uri, ok := os.LookupEnv("BP_TOMCAT_EXT_CONF_URI"); ok { + externalConfigurationDependency = &libpak.BuildpackDependency{ + ID: "tomcat-external-configuration", + Name: "Tomcat External Configuration", + Version: os.Getenv("BP_TOMCAT_EXT_CONF_VERSION"), + URI: uri, + SHA256: os.Getenv("BP_TOMCAT_EXT_CONF_SHA256"), + Stacks: []string{context.StackID}, + } + } + + base := NewBase(context.Application.Path, context.Buildpack.Path, b.ContextPath(), accessLoggingDependency, + externalConfigurationDependency, lifecycleDependency, loggingDependency, dc, &result.Plan) + + base.Logger = b.Logger + result.Layers = append(result.Layers, base) + + return result, nil +} + +func (Build) ContextPath() string { + cp := "ROOT" + if s, ok := os.LookupEnv("BP_TOMCAT_CONTEXT_PATH"); ok { + cp = s + } + cp = strings.TrimPrefix(cp, "/") + cp = strings.TrimSuffix(cp, "/") + cp = strings.ReplaceAll(cp, "/", "#") + + return cp +} diff --git a/tomcat/build_test.go b/tomcat/build_test.go new file mode 100644 index 0000000..b27bec2 --- /dev/null +++ b/tomcat/build_test.go @@ -0,0 +1,216 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tomcat_test + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/buildpacks/libcnb" + . "github.com/onsi/gomega" + "github.com/paketo-buildpacks/apache-tomcat/tomcat" + "github.com/paketo-buildpacks/libpak" + "github.com/sclevine/spec" +) + +func testBuild(t *testing.T, context spec.G, it spec.S) { + var ( + Expect = NewWithT(t).Expect + + ctx libcnb.BuildContext + ) + + it.Before(func() { + var err error + ctx.Application.Path, err = ioutil.TempDir("", "tomcat-application") + Expect(err).NotTo(HaveOccurred()) + + }) + + it.After(func() { + Expect(os.RemoveAll(ctx.Application.Path)).To(Succeed()) + }) + + it("contributes Tomcat", func() { + Expect(os.MkdirAll(filepath.Join(ctx.Application.Path, "WEB-INF"), 0755)).To(Succeed()) + + ctx.Buildpack.Metadata = map[string]interface{}{ + "dependencies": []map[string]interface{}{ + { + "id": "tomcat", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat-access-logging-support", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat-lifecycle-support", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat-logging-support", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + }, + } + ctx.StackID = "test-stack-id" + + result, err := tomcat.Build{}.Build(ctx) + Expect(err).NotTo(HaveOccurred()) + + Expect(result.Processes).To(ContainElements( + libcnb.Process{Type: "task", Command: "catalina.sh run"}, + libcnb.Process{Type: "tomcat", Command: "catalina.sh run"}, + libcnb.Process{Type: "web", Command: "catalina.sh run"}, + )) + + Expect(result.Layers).To(HaveLen(2)) + Expect(result.Layers[0].Name()).To(Equal("catalina-home")) + Expect(result.Layers[1].Name()).To(Equal("catalina-base")) + }) + + context("$BP_TOMCAT_VERSION", func() { + it.Before(func() { + Expect(os.Setenv("BP_TOMCAT_VERSION", "1.1.1")).To(Succeed()) + }) + + it.After(func() { + Expect(os.Unsetenv("BP_TOMCAT_VERSION")).To(Succeed()) + }) + + it("selects version based on $BP_TOMCAT_VERSION", func() { + Expect(os.MkdirAll(filepath.Join(ctx.Application.Path, "WEB-INF"), 0755)).To(Succeed()) + + ctx.Buildpack.Metadata = map[string]interface{}{ + "dependencies": []map[string]interface{}{ + { + "id": "tomcat", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat", + "version": "2.2.2", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat-access-logging-support", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat-lifecycle-support", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat-logging-support", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + }, + } + ctx.StackID = "test-stack-id" + + result, err := tomcat.Build{}.Build(ctx) + Expect(err).NotTo(HaveOccurred()) + + Expect(result.Layers[0].(tomcat.Home).LayerContributor.Dependency.Version).To(Equal("1.1.1")) + }) + }) + + context("$BP_TOMCAT_EXT_CONF_URI", func() { + it.Before(func() { + Expect(os.Setenv("BP_TOMCAT_EXT_CONF_SHA256", "test-sha256")).To(Succeed()) + Expect(os.Setenv("BP_TOMCAT_EXT_CONF_URI", "test-uri")).To(Succeed()) + Expect(os.Setenv("BP_TOMCAT_EXT_CONF_VERSION", "test-version")).To(Succeed()) + }) + + it.After(func() { + Expect(os.Unsetenv("BP_TOMCAT_EXT_CONF_SHA256")).To(Succeed()) + Expect(os.Unsetenv("BP_TOMCAT_EXT_CONF_URI")).To(Succeed()) + Expect(os.Unsetenv("BP_TOMCAT_EXT_CONF_VERSION")).To(Succeed()) + }) + + it("contributes external configuration when $BP_TOMCAT_EXT_CONF_URI is set", func() { + Expect(os.MkdirAll(filepath.Join(ctx.Application.Path, "WEB-INF"), 0755)).To(Succeed()) + + ctx.Buildpack.Metadata = map[string]interface{}{ + "dependencies": []map[string]interface{}{ + { + "id": "tomcat", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat-access-logging-support", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat-lifecycle-support", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + { + "id": "tomcat-logging-support", + "version": "1.1.1", + "stacks": []interface{}{"test-stack-id"}, + }, + }, + } + ctx.StackID = "test-stack-id" + + result, err := tomcat.Build{}.Build(ctx) + Expect(err).NotTo(HaveOccurred()) + + Expect(result.Layers[1].(tomcat.Base).ExternalConfigurationDependency).To(Equal(&libpak.BuildpackDependency{ + ID: "tomcat-external-configuration", + Name: "Tomcat External Configuration", + Version: "test-version", + URI: "test-uri", + SHA256: "test-sha256", + Stacks: []string{ctx.StackID}, + })) + }) + }) + + it("returns default context path", func() { + Expect(tomcat.Build{}.ContextPath()).To(Equal("ROOT")) + }) + + context("$BP_TOMCAT_CONTEXT_PATH", func() { + it.Before(func() { + Expect(os.Setenv("BP_TOMCAT_CONTEXT_PATH", "/alpha/bravo/")).To(Succeed()) + }) + + it.After(func() { + Expect(os.Unsetenv("BP_TOMCAT_CONTEXT_PATH")).To(Succeed()) + }) + + it("returns transformed context path", func() { + Expect(tomcat.Build{}.ContextPath()).To(Equal("alpha#bravo")) + }) + }) +} diff --git a/tomcat/detect.go b/tomcat/detect.go new file mode 100644 index 0000000..2a02a05 --- /dev/null +++ b/tomcat/detect.go @@ -0,0 +1,50 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tomcat + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/buildpacks/libcnb" +) + +type Detect struct{} + +func (d Detect) Detect(context libcnb.DetectContext) (libcnb.DetectResult, error) { + result := libcnb.DetectResult{ + Pass: true, + Plans: []libcnb.BuildPlan{ + { + Requires: []libcnb.BuildPlanRequire{ + {Name: "jre", Metadata: map[string]interface{}{"launch": true}}, + {Name: "jvm-application"}, + }, + }, + }, + } + + file := filepath.Join(context.Application.Path, "WEB-INF") + if _, err := os.Stat(file); err != nil && !os.IsNotExist(err) { + return libcnb.DetectResult{}, fmt.Errorf("unable to stat file %s\n%w", file, err) + } else if !os.IsNotExist(err) { + result.Plans[0].Provides = append(result.Plans[0].Provides, libcnb.BuildPlanProvide{Name: "jvm-application"}) + } + + return result, nil +} diff --git a/tomcat/detect_test.go b/tomcat/detect_test.go new file mode 100644 index 0000000..bbac263 --- /dev/null +++ b/tomcat/detect_test.go @@ -0,0 +1,83 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tomcat_test + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/buildpacks/libcnb" + . "github.com/onsi/gomega" + "github.com/paketo-buildpacks/apache-tomcat/tomcat" + "github.com/sclevine/spec" +) + +func testDetect(t *testing.T, context spec.G, it spec.S) { + var ( + Expect = NewWithT(t).Expect + + ctx libcnb.DetectContext + detect tomcat.Detect + path string + ) + + it.Before(func() { + var err error + path, err = ioutil.TempDir("", "tomcat") + Expect(err).NotTo(HaveOccurred()) + + ctx.Application.Path = path + }) + + it.After(func() { + Expect(os.RemoveAll(path)).To(Succeed()) + }) + + it("passes without WEB-INF", func() { + Expect(detect.Detect(ctx)).To(Equal(libcnb.DetectResult{ + Pass: true, + Plans: []libcnb.BuildPlan{ + { + Requires: []libcnb.BuildPlanRequire{ + {Name: "jre", Metadata: map[string]interface{}{"launch": true}}, + {Name: "jvm-application"}, + }, + }, + }, + })) + }) + it("passes with WEB-INF", func() { + Expect(os.MkdirAll(filepath.Join(path, "WEB-INF"), 0755)).To(Succeed()) + + Expect(detect.Detect(ctx)).To(Equal(libcnb.DetectResult{ + Pass: true, + Plans: []libcnb.BuildPlan{ + { + Provides: []libcnb.BuildPlanProvide{ + {Name: "jvm-application"}, + }, + Requires: []libcnb.BuildPlanRequire{ + {Name: "jre", Metadata: map[string]interface{}{"launch": true}}, + {Name: "jvm-application"}, + }, + }, + }, + })) + }) +} diff --git a/tomcat/home.go b/tomcat/home.go new file mode 100644 index 0000000..a441c10 --- /dev/null +++ b/tomcat/home.go @@ -0,0 +1,56 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tomcat + +import ( + "fmt" + "os" + + "github.com/buildpacks/libcnb" + "github.com/paketo-buildpacks/libpak" + "github.com/paketo-buildpacks/libpak/bard" + "github.com/paketo-buildpacks/libpak/crush" +) + +type Home struct { + LayerContributor libpak.DependencyLayerContributor + Logger bard.Logger +} + +func NewHome(dependency libpak.BuildpackDependency, cache libpak.DependencyCache, plan *libcnb.BuildpackPlan) Home { + return Home{LayerContributor: libpak.NewDependencyLayerContributor(dependency, cache, plan)} +} + +func (h Home) Contribute(layer libcnb.Layer) (libcnb.Layer, error) { + h.LayerContributor.Logger = h.Logger + + return h.LayerContributor.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + h.Logger.Bodyf("Expanding to %s", layer.Path) + if err := crush.ExtractTarGz(artifact, layer.Path, 1); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to expand Tomcat\n%w", err) + } + + layer.LaunchEnvironment.Override("CATALINA_HOME", layer.Path) + + layer.Launch = true + return layer, nil + }) +} + +func (Home) Name() string { + return "catalina-home" +} diff --git a/tomcat/home_test.go b/tomcat/home_test.go new file mode 100644 index 0000000..5ed9698 --- /dev/null +++ b/tomcat/home_test.go @@ -0,0 +1,68 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tomcat_test + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/buildpacks/libcnb" + . "github.com/onsi/gomega" + "github.com/paketo-buildpacks/apache-tomcat/tomcat" + "github.com/paketo-buildpacks/libpak" + "github.com/sclevine/spec" +) + +func testHome(t *testing.T, context spec.G, it spec.S) { + var ( + Expect = NewWithT(t).Expect + + ctx libcnb.BuildContext + ) + + it.Before(func() { + var err error + + ctx.Layers.Path, err = ioutil.TempDir("", "home-layers") + Expect(err).NotTo(HaveOccurred()) + }) + + it.After(func() { + Expect(os.RemoveAll(ctx.Layers.Path)).To(Succeed()) + }) + + it("contributes catalina home", func() { + dep := libpak.BuildpackDependency{ + URI: "https://localhost/stub-tomcat.tar.gz", + SHA256: "c31f9fd9b9458dd8dda54ce879dc7b08f8de0e638cb0936abcaa2316e7460c1e", + } + dc := libpak.DependencyCache{CachePath: "testdata"} + + h := tomcat.NewHome(dep, dc, &libcnb.BuildpackPlan{}) + layer, err := ctx.Layers.Layer("test-layer") + Expect(err).NotTo(HaveOccurred()) + + layer, err = h.Contribute(layer) + Expect(err).NotTo(HaveOccurred()) + + Expect(layer.Launch).To(BeTrue()) + Expect(filepath.Join(layer.Path, "fixture-marker")).To(BeARegularFile()) + Expect(layer.LaunchEnvironment["CATALINA_HOME.override"]).To(Equal(layer.Path)) + }) +} diff --git a/tomcat/init_test.go b/tomcat/init_test.go new file mode 100644 index 0000000..df348af --- /dev/null +++ b/tomcat/init_test.go @@ -0,0 +1,33 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tomcat_test + +import ( + "testing" + + "github.com/sclevine/spec" + "github.com/sclevine/spec/report" +) + +func TestUnit(t *testing.T) { + suite := spec.New("tomcat", spec.Report(report.Terminal{})) + suite("Base", testBase) + suite("Build", testBuild) + suite("Detect", testDetect) + suite("Home", testHome) + suite.Run(t) +} diff --git a/tomcat/setenv.sh b/tomcat/setenv.sh new file mode 100644 index 0000000..465cd75 --- /dev/null +++ b/tomcat/setenv.sh @@ -0,0 +1,2 @@ +# shellcheck disable=SC2034 +CLASSPATH="{{.classpath}}" diff --git a/tomcat/statik/statik.go b/tomcat/statik/statik.go new file mode 100644 index 0000000..871ee8e --- /dev/null +++ b/tomcat/statik/statik.go @@ -0,0 +1,14 @@ +// Code generated by statik. DO NOT EDIT. + +package statik + +import ( + "github.com/rakyll/statik/fs" +) + + +func init() { + data := "PK\x03\x04\x14\x00\x08\x00\x08\x00\xd5\xba{P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x00 \x00access-logging-support.shUT\x05\x00\x01\xc3\x8a~^<\xcb\xdf\n\x820\x14\x80\xf1\xfb=\xc5\xe1 \xde\xe5\x03\x04\xbb\x98\x7f\x90b\xa9\xe0\xe8\xc6d\x98-\x11\xec(sB \xbe{P\xd2\xe5\x07\xdf/\xc9D(\x93\x98{kXH\xad\xf2K$\x94\x16Q\x94\x94\xa5\x96y\x9a\x9e\xb2\xf4\xc8ic\xac\xaa\x00\xbdu\xdf7\x04\x0eH\x08u\x0d\xbe\x0f\xd6\xb8\xc5\x12c\x93\xed\xc9=\x01\xd5\xf8j\x1b\x07\xa2m\xcd<\x83\x1c\xbb\xae\xa7\x0e\x0c5\xf7\xc1\x01\x00\x00\xff\xffPK\x07\x08U\xf5\xdcm\x9c\x00\x00\x00\xb5\x00\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\xd3\xab~P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00 \x00setenv.shUT\x05\x00\x01\xfed\x82^RV(\xceH\xcd\xc9I\xceHM\xceVH\xc9,NL\xcaI\xb5\x0dv6206\xe1r\xf6q\x0c\x0e\x0ep\x0c\xf1\xb0U\xaa\xae\xd6K\xceI,..H,\xc9\xa8\xadU\xe2\x02\x04\x00\x00\xff\xffPK\x07\x08\xee\x8c\x05\xde=\x00\x00\x007\x00\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\xd5\xba{PU\xf5\xdcm\x9c\x00\x00\x00\xb5\x00\x00\x00\x19\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00access-logging-support.shUT\x05\x00\x01\xc3\x8a~^PK\x01\x02\x14\x03\x14\x00\x08\x00\x08\x00\xd3\xab~P\xee\x8c\x05\xde=\x00\x00\x007\x00\x00\x00 \x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xec\x00\x00\x00setenv.shUT\x05\x00\x01\xfed\x82^PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x90\x00\x00\x00i\x01\x00\x00\x00\x00" + fs.Register(data) + } + \ No newline at end of file diff --git a/tomcat/testdata/060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6.toml b/tomcat/testdata/060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6.toml new file mode 100644 index 0000000..22a33a0 --- /dev/null +++ b/tomcat/testdata/060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6.toml @@ -0,0 +1,2 @@ +uri = "https://localhost/stub-external-configuration-with-directory.tar.gz" +sha256 = "060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6" diff --git a/tomcat/testdata/060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6/stub-external-configuration-with-directory.tar.gz b/tomcat/testdata/060818cbcdc2008563f0f9e2428ecf4a199a5821c5b8b1dcd11a67666c1e2cd6/stub-external-configuration-with-directory.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..9013334c999db672133b35e917d5eaa5713a3967 GIT binary patch literal 168 zcmV;Z09XGXiwFSV4KiK;1MQJP4#FT1ML7x=XdK#^;XG(S8!Jr^k{(~uHm2mk;T{Gu6>+C5i-O0}V_rHkmO8NZF?sWSF zbB~{8>(?&1EOmO$sSB+gGgehU%Xm1osP26Hx%j3PnG(KpD!wjjo^1F0Pj+-~s{K=| gqpGrBzD1p5|9xJ5KMMmgSg@Ggw4|4nL4$z-0MDvB2LJ#7 literal 0 HcmV?d00001 diff --git a/tomcat/testdata/723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534.toml b/tomcat/testdata/723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534.toml new file mode 100644 index 0000000..ab3bc78 --- /dev/null +++ b/tomcat/testdata/723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534.toml @@ -0,0 +1,2 @@ +uri = "https://localhost/stub-tomcat-lifecycle-support.jar" +sha256 = "723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534" diff --git a/tomcat/testdata/723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534/stub-tomcat-lifecycle-support.jar b/tomcat/testdata/723126712c0b22a7fe409664adf1fbb78cf3040e313a82c06696f5058e190534/stub-tomcat-lifecycle-support.jar new file mode 100644 index 0000000000000000000000000000000000000000..81740cf40e49cfffa346a848d7a866513ccf0420 GIT binary patch literal 437 zcmWIWW@Zs#;Nak3xb9USz<>le8CV#6T|*poJ^kGD|D9rBU}gyLX6FE@V1gPCoIpGPtEvL^s$H$Z27$&wQbfwqd^#CITr&1&_PGgT+RoSP0Oq( zDJ@FX%}p%IPAv-XW@Hj!K=mig6Ci)00=UCLzDC!I>;#Z65x^G6glk3eGspxk2HZ|X Yn6L}TM0YqV8%UlR2zLVMXCMv(01$UnfdBvi literal 0 HcmV?d00001 diff --git a/tomcat/testdata/c31f9fd9b9458dd8dda54ce879dc7b08f8de0e638cb0936abcaa2316e7460c1e.toml b/tomcat/testdata/c31f9fd9b9458dd8dda54ce879dc7b08f8de0e638cb0936abcaa2316e7460c1e.toml new file mode 100644 index 0000000..90faa2c --- /dev/null +++ b/tomcat/testdata/c31f9fd9b9458dd8dda54ce879dc7b08f8de0e638cb0936abcaa2316e7460c1e.toml @@ -0,0 +1,2 @@ +uri = "https://localhost/stub-tomcat.tar.gz" +sha256 = "c31f9fd9b9458dd8dda54ce879dc7b08f8de0e638cb0936abcaa2316e7460c1e" diff --git a/tomcat/testdata/c31f9fd9b9458dd8dda54ce879dc7b08f8de0e638cb0936abcaa2316e7460c1e/stub-tomcat.tar.gz b/tomcat/testdata/c31f9fd9b9458dd8dda54ce879dc7b08f8de0e638cb0936abcaa2316e7460c1e/stub-tomcat.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3d9527095d81842dd6af595be07dca87b215a0eb GIT binary patch literal 177 zcmb2|=3w~uTQHV^`R&E~TulZd#|!0C^%uxKfA*qqnorN9B;6MuCr?>-q+`#-ee-AE zKg##!&&TllC5ryj_kGm7FCO%wX!=@jmpNNsP5nA!(b*ZopQ*(EJusi$lT`xCH;!;Yi(M8e3n0KmzBJ4=YHd; dbg!@(?-$$ew`V{C4R5QMGAgG%V$fh<006A9SZ)9S literal 0 HcmV?d00001 diff --git a/tomcat/testdata/d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2.toml b/tomcat/testdata/d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2.toml new file mode 100644 index 0000000..2116734 --- /dev/null +++ b/tomcat/testdata/d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2.toml @@ -0,0 +1,2 @@ +uri = "https://localhost/stub-tomcat-access-logging-support.jar" +sha256 = "d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2" diff --git a/tomcat/testdata/d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2/stub-tomcat-access-logging-support.jar b/tomcat/testdata/d723bfe2ba67dfa92b24e3b6c7b2d0e6a963de7313350e306d470e44e330a5d2/stub-tomcat-access-logging-support.jar new file mode 100644 index 0000000000000000000000000000000000000000..92264efe4c87fb3eeb19aca147f4b1b2d5d6d856 GIT binary patch literal 437 zcmWIWW@Zs#;Nak3IOJ6yz<>le8CV#6T|*poJ^kGD|D9rBU}gyLX6FE@V1gPCoIpGPtEvL^s$H$Z27$&wQbfwqd^#CITr&1&_V0aT+RoSP0Oq( zDJ@FX%}p%IPAv-XW@Hj!K=mig6Ci)00=UCLzDC!I>;#Z65x^G6glk3eGspxk2HZ|X Yn6L}TM0YqV8%UlR2zLVMXCMv(0GWDJ0RR91 literal 0 HcmV?d00001 diff --git a/tomcat/testdata/e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c.toml b/tomcat/testdata/e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c.toml new file mode 100644 index 0000000..7022f45 --- /dev/null +++ b/tomcat/testdata/e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c.toml @@ -0,0 +1,2 @@ +uri = "https://localhost/stub-tomcat-logging-support.jar" +sha256 = "e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c" diff --git a/tomcat/testdata/e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c/stub-tomcat-logging-support.jar b/tomcat/testdata/e0a7e163cc9f1ffd41c8de3942c7c6b505090b7484c2ba9be846334e31c44a2c/stub-tomcat-logging-support.jar new file mode 100644 index 0000000000000000000000000000000000000000..05f3a45123461b9ba981294f38f7b9efa0a4a9b1 GIT binary patch literal 437 zcmWIWW@Zs#;Nak3c;Zzbz<>le8CV#6T|*poJ^kGD|D9rBU}gyLX6FE@V1gPCoIpGPtEvL^s$H$Z27$&wQbfwqd^#CITr&1&_OrQT+RoSP0Oq( zDJ@FX%}p%IPAv-XW@Hj!K=mig6Ci)00=UCLzDC!I>;#Z65x^G6glk3eGspxk2HZ|X Yn6L}TM0YqV8%UlR2zLVMXCMv(0Abfu-2eap literal 0 HcmV?d00001