This cookbook gives more in-depth knowledge to some selected deployment topics, including:
It is in the nature of Gradle that the lines between configuration and extension, administration and development blur. That is why this cookbook addresses administrators and developers and concerns development and deployment time.
The cookbook is mostly self-contained. Knowledge of the Concept - Gradle Deployment Tools is not required to follow the recipes, but helpful for a deeper understanding and straying off the predefined course.
Phrase | Meaning |
---|---|
Version Control System (VCS) | Also known as source control, source code management systems (SCM), or revision control systems (RCS). VCS is a mechanism for keeping multiple versions of your files, so that when you modify a file you can still access the previous revisions. |
Artifact Repository | Place, where build and package software components are located. Provide a common interface to a dependency management system. |
Code Analysis | Process to analyze source code to calculate metrics, find bugs, etc. |
Continuous Delivery Pipeline | Sometimes called Deployment Pipeline, describes the stages, which code artifacts runs through source to production system. |
System Component | A software package of different code artifacts and files, that have to be deployed together. |
System Component Set | Is a container for system components, that needs to be build and branched together. |
Assembly | An assembly references one or more system components residing in the same or a configured artifact repository in order to deploy or deliver them together. |
Build Process | Compiles and packages files and code artifacts from a source project to deployable artifacts. |
Publish Process | The process which transfers the deployable artifacts to a configured artifact repository. |
Assembly Process | This process combines several system components to an assembly. |
Deployment Process | This process extracts files and code artifacts from an artifact repository and applies the configuration. |
Project Gradle Distribution | This is a customized Gradle distribution with the preconfigured artifact repositories and Gradle plugins. |
Gradle Plugin | A Gradle plugin packages up reusable pieces of build logic, which can be used across many different projects and builds. |
Project Gradle Plugin | This is a Gradle plugin which contains special corporate respectively project settings. |
Corporate Plugin | The term is used as a synonym for Project Gradle Plugin. |
Gradle Extension Object | Java Bean compliant class holding configurations for Gradle plugins. |
Gradle Wrapper | The Gradle Wrapper is the preferred way of starting a Gradle build. The wrapper is a batch script on Windows, and a shell script for other operating systems. When you start a Gradle build via the wrapper, Gradle will be automatically downloaded and used to run the build. See for more information The Gradle Wrapper in the Gradle documentation (2.11, 2.7, 2.3, 2.0, 1.8) |
Intershop Cluster | A number of hosts of different types serving an Intershop 7. |
Cluster Node | One separately deployable part of an Intershop cluster. A host can run multiple nodes of one Intershop cluster. |
Before executing a deployment the host and its environment must be prepared.
Prerequisites for executing a deployment are:
Developers can use a deployment that is triggered inside the assembly process and that requires only a simple properties file for configuration.
For more information, refer to the corresponding Gradle Developer Workflow cookbook:
You may use a standard Gradle distribution available from http://www.gradle.org, download it and extract it.
Note
Before downloading, check which Gradle Tools version you are using to find the right version.
Intershop Gradle Tools always correspond to a certain Gradle / ICM version. For more information on version dependencies, see Reference - CI Dependencies of Intershop Commerce Management.
You may also use a project Gradle distribution, as created through the corresponding Setup CI Infrastructure cookbook in your artifact repository. This has the advantage that the repositories are preconfigured automatically.
You may either download the Gradle distribution manually or use a Gradle wrapper - a small Java program that will download Gradle, extract it and run it automatically. It is recommended to store and retrieve the Gradle wrapper from a VCS.
See also the corresponding Gradle user guide on the Gradle Wrapper:
The corresponding Setup CI Infrastructure cookbook helps you to create a wrapper:
The deployment copies files to deploy from an artifact repository. The repository is filled by a build process/copying pre-built components from other repositories. Two main types of repositories are
Making them accessible may thus mean to mount an NFS or a DVD or opening firewalls. To tell Gradle where the repositories can be found refer to the Recipe: Configure the Deployment.
Gradle stores caches and configurations in a folder called Gradle user home. When using a remote repository (i.e., URL, not file system based), this can become quite large. The default location at <OS user home>/.gradle may not be the best place in this case. Reconfigure the location by setting the environment variable GRADLE_USER_HOME
.
Gradle itself is a general purpose automation tool. The central file telling Gradle what to automate is the Gradle settings file, typically called settings.gradle.
For the deployment it contains:
deployment-bootstrap
plugin.See Recipe: Configure the Deployment for details about the contents of this file.
Also see the Concept - Gradle Deployment Tools and the corresponding Gradle user guide on Multi-project Builds (2.11, 2.7, 2.3, 2.1, 1.8).
The settings file can be stored anywhere in the local file system, except any folder which is processed by the deployment. We recommend to put it into the parent folder of your deployment (if you deploy into a single directory). If the local deployment script is called settings.gradle and located in the current working directory or any parent directory Gradle will automatically find it. If you differ from naming or location, you have to pass in the Gradle command line option -c
, --settings-file
, upon every execution, see the corresponding Gradle user guide on command line usage (2.11, 2.7, 2.3, 2.1, 1.8).
We recommend to store the settings.gradle in a VCS or use a configuration management tool to generate/distribute it.
To execute the deployment run the Gradle command (gradlew
for invocation through the wrapper or gradle
for direct invocation) in the directory of the settings file and pass a Gradle task to execute. Available tasks can be displayed by:
<gradle command> tasks
When deploying an Intershop 7 based solution additional system prerequisites must be met - like an installed Oracle client and a prepared database.
Before executing a deployment must be configured in the settings.gradle file.
To configure your deployment create a settings.gradle file, containing the following information:
The general structure of a settings.gradle for deployment is:
buildscript { gradle.injectRepositories(repositories, configurations) dependencies { classpath 'com.intershop:deployment-bootstrap:<version>' } } apply plugin: com.intershop.deploy.bootstrap.DeploymentBootstrapPlugin deploymentBootstrap { gradle.injectRepositories(repositoryHandler, configurationContainer) // assembly block assembly ('<assembly organization>:<assembly name>:<assembly version>') { hostType { environment '<environment>' hostType '<host type>' } } // config block config { <config DSL block> } }
The deployment requires repositories to resolve the assembly, all components to deploy and the deployment plugins from. The settings.gradle template above assumes, that
injectRepositories
on the global gradle
object. RepositoryHandler
and a ConfigurationContainer
RepositoryHandler
and may optionally control details of the dependency resolution process on the ConfigurationContainer
objectThis closure is best provided in a Gradle init script. The Project Gradle Plugin created with Cookbook - Setup CI Infrastructure (valid to GradleTools 1.1) already provides this closure. Using a Project Gradle Distribution (directly or through a Gradle wrapper) will therefore automatically declare the repositories.
You may also declare them manually in a Gradle init script as shown in the following example:
gradle.ext.injectRepositories = { RepositoryHandler repositories, ConfigurationContainer configurations -> repositories.with { // Declare repositories using Gradle's repository DSL maven { url "http://repo.mycompany.com/maven2" } ivy { url "http://repo.mycompany.com/repo" layout "pattern", { artifact "[module]/[revision]/[type]/[artifact].[ext]" } } } }
See Gradle user guide on Dependency Management or Gradle DSL documentation on
RepositoryHandler
for details on how to declare repositories.
The deployment must know which assembly to deploy. Also it must determine - very early in deployment - which components to create as projects (see Concept - Gradle Deployment Tools), based on host type and environment to deploy. See Concept - Continuous Delivery Tools (valid to 7.10) (in the sections Assembly Subsset Host Type and Assembly Subset Environment) and Concept - Gradle Assembly Tools for a general definition of what a host type and an environment is and which ones are available by default.
Options (defined by assembly) | |
---|---|
hostType | all, webserver,appserver,solr,share with IS 7.8.0.1: discoveryserver, microservices |
environment | development, test, production |
The config
block configures the root level Gradle project during deployment, which represents the assembly. It contains most significant deployment configurations. It is segmented into sub-blocks.
The following tables gives an overview about sub-blocks of the config
block and their properties. The last three columns show for which host-types they are required.
Configuration | Structure | Description | Example | appserver | share | webserver |
---|---|---|---|---|---|---|
Java directory | target.javaHome = File | Specify the JDK which should be used in scripts, e.g. to execute the server-startup. (DEFAULT) By default this Value is set to the Java which executes the Gradle-Process. JDK lookup mechanism: Gradle tries to find a JDK installation, if the Gradle-Process is executed via a JRE based in a JDK's directory. E.g.:
The mechanism doesn't work, if target.javaHome is configured. In this case target.javaHome must point to a valid JDK directory with jre directory inside. | target { javaHome = new File( '/path/to/jdk' ) // must reference to a jdk directore (see below)}
[/ or C:\] |-- path
| ![]() | ![]() | ![]() |
Share directory | target.shareDirectory = File | Specify the share directory to deploy to (IS_SHARE).
| target { } | ![]() | ![]() | ![]() |
Local directory | target.localDirectory = File | Specify the local directory (IS_HOME)
| target { | ![]() | ![]() | |
Application server settings | appserver { | Configuration relevant for all appservers of the installation. The nodemanagerNetworkInterface defaults to 127.0.0.1. The hostname defaults to localhost for single-machine installations. | appserver { | ![]() | ||
Appserver instances | appserver { | Specify the appserver instances. For each instance add a block for the application server. The ports must be unique and unused on the target system. Even, if not required, stay with the naming schema 'appserver0', 'appserver1', etc. Server groups are optional and default to Appserver-specific configuration is stored in IS_HOME/config per default, but can be configured via appserver.configPath. | appserver { appserver1 { | ![]() | ||
Database account (Gradle Tools ≤ 1.1) | database { | Specificy the database settings. | database { | ![]() | ||
Database account (Gradle Tools ≥ 2.0) | database { | Specificy the database settings. SID-based configuration is deprecated, prefer to use service name to designate the database instance. | database { | ![]() | ||
License file | license.licenseFile = File | Specify the path to your license file. The file must be available at your target system. | license { | ![]() | ||
Instance ID | target.instanceId = '<FILL IN>' | Specify the ID of your instance. The ID must be unique on your target system. | target.instanceId = '9' | ![]() | ![]() | ![]() |
Platform ID | target.platform = '<FILL IN>' | Specify the ID of your platform. Supported values are:
| target { | ![]() | ![]() | |
Web Adapter settings | webadapter { | Specify the settings for running the Web Adapter.
| webadapter { | ![]() | ||
Web Adapter settings (for share only) | webadapter { | Specify the settings how to generate public URLs directed at a Web Adapter (or load balancer). | webadapter { | ![]() | ||
External SSL box configuration (Gradle Tools ≥ 2.0) | webadapter { | Specifies whether or not an external SSL box is being used, and which port the Web Adapter should listen to for secured connections .useSSLBox defaults to false . | webadapter { | |||
Multicast settings (until Gradle Tools 1.0) | multicast { | Specify the multicast addresses, ports and (optionally) interfaces to bind to. | multicast { | ![]() | ||
Multicast settings (Gradle Tools ≥ 1.1, for share only) | multicast { | Specify the multicast addresses and ports. This part of the multicast configuration applies cluster-wide. | multicast { cache { | ![]() | ||
Multicast settings (Gradle Tools ≥ 1.1, for appserver only) | multicast { | Specify the network interface to bind multicast connections to. This part of the multicast configuration applies to the deployed appserver only. | multicast { | ![]() | ||
AWS (Amazon Web Service) messaging settings (Gradle Tools ≥ 2.1) | aws { tcm { cache { orm { all { } | Specify cluster-wide AWS messaging settings for each messenger channel. The all block can be used to specify common messenger settings. | aws { all { tcm { cache { orm { } | ![]() | ||
User settings | assemblyDeployment.user = '<FILL IN>' | Specify the user to run the deployed application with. The user will not be created during setup. Your need to create it before the deployment starts. You have to execute the deployment with this user. | assemblyDeployment { | ![]() | ![]() | |
Solr search service (Gradle Tools ≥ 2.0) | solr { | Configures the Solr search service in IS7.
| solr { | (![]() | ||
Tomcat servlet container (Gradle Tools ≥ 2.0) | tomcat { | Configures tomcat servlet container instances. Each instance is extensible and may be marked for specific use cases, e.g. Solr search server configuration below. | tomcat { | |||
Java VM settings (Gradle Tools ≥ 2.0) | tomcat { | Configures the Java VM used to start the servlet container instances. Allows configuration of memory settings (in MB) and directly passing in additional arguments. In case of additionalJvmArgs containing a equal sign, use unicode-encoded double quotes | tomcat { | |||
Solr search server (Gradle Tools ≥ 2.0) | tomcat { | Configures which Tomcat instances will act as Solr search servers. Required for hosts of host type solr. | tomcat { |
Within ICM 7.8 the microservices were introduced. These and other ICM components (application server, the solr server, web adapter agent) may register at a eureka server. This enables the micro-services to find the appserver (and vice versa) and a recurring order can be triggered.
The following table is valid from IS 7.8.0.1 and shows which extensions need to be added and configured for the different host types:
Configuration | Extension | Description | Example | hostType share | hostType webserver | hostType solr | hostType discoveryserver | hostType microservices |
---|---|---|---|---|---|---|---|---|
local eureka server deployment | eureka | Provides the possiblity to install a local eureka server. | eureka { serverHostName = '127.0.0.1' serverPort = '12345' serverUrlPath = 'eureka/' } | ![]() | ||||
eureka registration url | eureka | The url, which clients use to register at eureka | ![]() | ![]() | ![]() | ![]() | ||
serviceAppName | appserver | The name the application server is using to register at eureka. | appserver{ serviceAppName = 'appServerName' } | ![]() | ![]() | ![]() | ||
serviceAppName | solr | The name the solr server is using to register at eureka. | solr{ serviceAppName = 'solrServerName' } | ![]() | ![]() | |||
microservices: general configuration | microservices | The configuration of the microservices. It contains information about the database connection, the port the microservices are running and the name the microservices are using to register at eureka | microservices { port = '<MY_PORT>' name = 'microserviceName' instanceId= 'microserviceInstanceId' configProperties[ 'javax.persistence.jdbc.url' ] = '<CONNECTION_URL_DATABASE>' configProperties[ 'javax.persistence.jdbc.user' ] = '<DATABASE_USER>' configProperties[ 'javax.persistence.jdbc.password' ] = '<DATABASE_PASSWORD>' | ![]() | ||||
mircroservice: naming mapping | microservices | It contains information about the names of the microservices. | configProperties[ 'intershop.naming.service.RecurringOrder' ] = 'microserviceName' configProperties[ 'intershop.naming.service.Scheduling' ] = 'microserviceName' } | ![]() | ![]() |
For further information, please see the following recipes:
Info
I do not want to deploy cartridges into the shared directory. How can I deploy cartridges to a custom location?
You can change the location where cartridges are deployed, e.g., into the IS_HOME directory.
Moving the cartridge location across host types (e.g., from share to appserver) is not a deployment configuration, but requires modification of host types during the build of your assembly, see Concept - Gradle Assembly Tools.
In your Assembly's build.gradle file the includeCartridges
flag of a host type controls, whether cartridges will be deployed for this particular host type. By default, this flag will only be true
for host type share (and therefore also for all).
To move cartridges from IS_SHARE to IS_HOME, you need to
includeCartridges=true
for host type appserverincludeCartridges=false
for host type shareThis will
If you do not want your cartridges to reside in either IS_SHARE/system/cartridges or IS_HOME/cartridges, you can specify a custom cartridge location inside your deployment's settings.gradle script. You still need to adjust the host type's flags according to the previous section.
Use Code Examples The code examples provided in this recipe can be copied to the During development you can create a deploy.gradle, which will be used automatically. See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).deploymentBootstrap.config
block of the settings.gradle at deployment time....
deploymentBootstrap {
...
config {
// Insert code examples here
}
}
// Insert code examples here
target { cartridgesPath = '$PLACEHOLDER/relative/path/to/cartridges' }
In case the cartridges are going to reside on
${IS_HOME}
will become target.localDirectory
${IS_SHARE}
will become target.shareDirectory
Note
Cluster Configuration
The cartridge location must be uniform inside your cluster!
Info
There is an own settings.gradle for each host type. According to an already created ivy.xml the cartridges are deployed to the <IS_SHARE> directory, but we want the cartridges within <IS_HOME>.
Prefer the solution Recipe - Configure Cartridge Location, if possible.
includeCartridges = false
to the target extension of the settings.gradle for host type share.hostType.includeCartridges = false
to the host type extension of the settings.gradle for host type appserver.The ivy.xml, which the deployment is based on, shows the cartridges that should be deployed for host type 'share', which means they are deployed into <IS_SHARE>:
... <e:hostType name="appserver" includeCartridges="false" includeShare="false" includeLocal="true" includeJavadoc="false"/> <e:hostType name="share" includeCartridges="true" includeShare="true" includeLocal="false" includeJavadoc="false"/> ...
To adapt the deployment locations to <IS_HOME>, the settings.gradle of the host type 'share'
and 'appserver'
need to be adapted:
hostType { hostType 'appserver' hostType.includeCartridges = true }
target { includeCartridges = false }
Since Gradle tools Version >= 2.0.
Intershop 7 can encrypt sensitive database content. To decrypt data the same algorithm and key has to be used like for encryption.
Also it must be possible to use a different algorithm/key starting with a certain point in time to increase security.
Encryption is configured in three files:
One of the encryption configurations in the properties file is marked as default configuration. It is used for all encryption processes. Other encryption configurations are used to decrypt data that was encrypted when that configuration was default.
The keystore is protected against unwanted reading and writing by a password. The password is calculated from several different pieces of data. One of them is contained in the properties file, another is the content of the random file.
These three files are provided as input files to the deployment. Like other deployment input files, they become part of the desired state and should be kept under management of an external tool (like a VCS) to be able to restore them on machine failure. Encryption configuration is not modified, but only read by the application (Intershop 7).
Configuring encryption consists of two parts:
See discussion for details.
The tasks described in the following sections are provided by the EncryptionAdminPlugin
.
They can be executed using a settings.gradle for deployment. Also, you can run them from a standalone Gradle script, applying the EncryptionAdminPlugin
:
buildscript { dependencies { classpath 'com.intershop:deployment-bootstrap:+' } } apply plugin: com.intershop.deploy.encryption.EncryptionAdminPlugin encryption { propertiesFile = file('encryption.properties') keystoreFile = file('intershop.keystore') randomFile = file('random') algorithm = 'PBEWithMD5AndTripleDES' }
The above example stores/loads the encryption configuration files in the same folder as the build.gradle file. You may specify a different location by setting propertiesFile
, keystoreFile
and randomFile
to different Java File
objects, e.g., propertiesFile = new File('/home/is7admin/encryption.properties')
.
When executing the tasks during deployment, the files are by default expected in the same folder as the settings.gradle file, see section "Deploy Encryption Configuration" below.
The algorithm
property in the encryption
block specifies both,
It must be of the form PBEWith<digest>And<encryption>
, see Standard Algorithm Name Documentation for JDK 8 or JDK 7, depending on your version.
To create the encryption configuration files initially, including a new encryption configuration and key, run the Gradle task generateEncryptionConfig
. This task is called automatically as part of the normal deployment.
The generateEncryptionConfig
task is idempotent:
algorithm
property.This ensures that after running this task there is always a valid encryption configuration using the specified algorithm, but existing database content can still be decrypted.
To use a different encryption/key generation algorithm in future, simply:
algorithm
propertygenerateEncryptionConfig
taskTo generate a new key, even with the same algorithm as the current default configuration, run the Gradle task newKey
.
To generate a new random password for the keystore, run the Gradle task newPassword
. This changes the random file, the password data in the properties file and rewrites the keystore file using the new password.
Encryption configuration files are deployed using the EncryptionDeploymentPlugin
, applied by default. You may specify:
Use Code Examples The code examples provided in this recipe can be copied to the During development you can create a deploy.gradle, which will be used automatically. See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).deploymentBootstrap.config
block of the settings.gradle at deployment time....
deploymentBootstrap {
...
config {
// Insert code examples here
}
}
// Insert code examples here
encryption { // Paths to the configuration files to deploy from // TODO: Adapt paths or remove if the defaults suffice propertiesFile = new File('/opt/install/encryption.properties') keystoreFile = new File('/opt/install/intershop.keystore') randomFile = new File('/opt/install/random') // Paths relative to IS_SHARE, that the files should be deployed to // TODO: Adapt paths or remove if the defaults suffice propertiesTargetPath = 'system/encryption/encryption.properties' keystoreTargetPath = 'system/encryption/intershop.keystore' randomTargetPath = 'system/encryption/random' }
Note
In production make sure to limit file system permissions to the encryption configuration! This may be easier when deploying them to a different folder than <IS_SHARE>/system/config/cluster. Minimum permissions are read/write permissions for the user running deployment and application server.
If EncryptionDeploymentPlugin
and EncryptionAdminPlugin
are applied both (by default), encryption configuration files are automatically generated/adapted before deployment. Especially the default algorithm is changed to the algorithm configured in the encryption
block, by default to the weak "PBEWithMD5AndTripleDES". To prevent the deployment from changing the encryption configuration in production, add the following line:
generateEncryptionConfig.enabled = false
Since Gradle tools Version >= 2.0.
The password that is used for connecting the Intershop 7 application with an Oracle database is stored in the <IS_SHARE>/system/config/cluster/orm.properties file. This is the default location though it is possible to change it. The password might be stored as a plain text:
intershop.jdbc.user=INTERSHOP intershop.jdbc.password=intershop
If you make your shared file system accessible to a larger group of people (like your support department), but do not want to grant full database access, encrypt your database password.
encrypt
task in a deployment or pre-deployment environment, see discussion.To encrypt the database password, run the Gradle task encrypt
provided by the EncryptionAdminPlugin
. It can be executed using a settings.gradle for deployment. Also, you can run them from a standalone Gradle script, applying the EncryptionAdminPlugin
, see Recipe: Configure Encryption for details.
In any of the two environments, run (replacing yourPasswordInPlainText
by your actual database password):
<gradle command> encrypt -PplainText=yourPasswordInPlainText
The resulting output shows your decrypted password (in the example: encryption1@PBEWithMD5AndTripleDes:5FY97GDnsvU=|3viFU8xFc1XmMhLnPXeWcVWDGgX/WUta
)
:generateEncryptionConfig :encrypt Encrypted text for plain text 'yourPasswordInPlaintext': encryption1@PBEWithMD5AndTripleDes:5FY97GDnsvU=|3viFU8xFc1XmMhLnPXeWcVWDGgX/WUta
(Running the command with -q
will only output the encrypted password.)
Hint
Encrypting the same password over and over again always yields different results with the default algorithm. This is normal because the encryption text is salted. In this way semantic security is guaranteed.
In the database
block of your settings.gradle for the deployment as prepared in Recipe: Configure the Deployment:
password
.passwordIsEncrypted
with value true
.Given the encrypted password in the example above the result looks like this:
... deploymentBootstrap { ... config { ... database { host = 'localhost' port = 1521 serviceName = 'ISORCL1.world' tnsAlias = 'ISSERVER.world' user = 'dbuser' password = 'encryption1@PBEWithMD5AndTripleDes:5FY97GDnsvU=|3viFU8xFc1XmMhLnPXeWcVWDGgX/WUta' passwordIsEncrypted = true oracleClientDir = new File('C:/path/to/oracle/client/dir') } } }
After the deployment the resulting entries in the <IS_SHARE>/system/config/cluster/orm.properties look like this:
intershop.jdbc.user=dbuser intershop.jdbc.password.encrypted=true intershop.jdbc.password=encryption1@PBEWithMD5AndTripleDes:5FY97GDnsvU=|3viFU8xFc1XmMhLnPXeWcVWDGgX/WUta
I want to deploy systems, that participate in a replication environment.
Use none
if the instance to be deployed will not participate in a replication cluster.
Use editing
if the instance to be deployed will only provide mass data for the replication environment.
Use live
if the instance to be deployed will receive mass data in a replication environment.
This also applies if it is not the last system of a replication chain.
Applying StagingDeploymentPlugin (which is part of IntershopPlugins) will let you configure data replication via the following DSL:
staging { systemType = 'editing' | 'live' | 'none' replicationClustersFile = new File('<FILL IN>') }
This will:
live
systems:.active
flag) will not be overwritten by deploymentBe aware that deployment of a live
system will reset your replicated content.
Please consider updating to a newer release of Gradle Tools. As a workaround, you may define a custom modification handling strategy as defined in the Recipe: Keep Local Modifications:
keep('stagedFiles') { priority '<YourPriority>' dir project.target.shareDirectory include 'sites/*/?/**' include 'sites/*/.active' include 'system/config/cluster/solr/solr.xml' }
Starting with Intershop Commerce Management Suite 7.6 (B2C,
B2X) the delivered assemblies no longer include cartridges that define the storefront applications and do not provide the storefront functionality, meaning the view layer with the content model. Instead, Intershop provides the Responsive Starter Store. This includes the storefront parts as a source project that can be used as a blue print to set up customer projects.
After creating the project source structure from the Intershop templates it is necessary to fill the project with the specific artifacts, especially those that make up the storefront. The Responsive Starter Store is a good starting point, that provides the functionality, code artifacts and demo content of a standard responsive storefront.
How can a build engineer or developer set up a project based on the Responsive Starter Store?
Note
License
Please make sure to comply with Glyphicons Free license terms (CC BY 3.0) or get pro license.
See the following recipes:
Note
The following listings contain diff-style where "<DIFF>" leads the listing title.
This describes changes on files where "-String=original line of code;
" represents the original line of code that should be replaced with "+String=replaced line of code
'".
See the following sections for details.
Note
Newer versions of the responsive starter store
Find the Responsive Starter Store version and download links for a corresponding Intershop Commerce Management version in the Reference - CI Dependencies of Intershop Commerce Management.
Responsive Starter Store version 3.1.4 for Intershop Commerce Management 7.8:
Download the Responsive Starter Store multi project (a_responsive
).
http://<your-reposerver:port>/nexus/content/repositories/ishrepo/com.intershop.public.source/a_responsive/3.1.4/zips/a_responsive-zip-src-3.1.4.zip
Responsive Starter Store version 4.0.0 for Intershop Commerce Management 7.9
Download the Responsive Starter Store multi project (a_responsive
).
http://<your-reposerver:port>/nexus/content/repositories/ishrepo/com.intershop.public.source/a_responsive/4.0.0/zips/a_responsive-zip-src-4.0.0.zip
Responsive Starter Store version 32.2.4 for Intershop Commerce Management 7.10
Download the Responsive Starter Store multi project (a_responsive
).
http://<your-reposerver:port>/nexus/content/repositories/ishrepo/com.intershop.public.source/a_responsive/32.2.4/zips/a_responsive-zip-src-32.2.4.zip
Content Overview of the Responsive Starter Store multi project:
a_responsive |-- app_sf_responsive |-- app_sf_responsive_b2b |-- app_sf_responsive_b2b_test |-- app_sf_responsive_b2c |-- app_sf_responsive_cm |-- app_sf_responsive_costcenter |-- app_sf_responsive_smb |-- app_sf_responsive_test |-- as_responsive |-- as_responsive_b2b |-- demo_responsive |-- demo_responsive_b2b |-- demo_responsive_catalog |-- demo_responsive_content |-- demo_responsive_ocst |-- demo_responsive_search |-- dev_storefront |-- gradle |-- inspired-b2c |-- inspired-b2x |-- microservices |-- .ivyIcm-b2c.version |-- .ivyIcm-b2x.version |-- build.gradle |-- gradle.properties |-- gradlew |-- gradlew.bat `-- settings.gradle | responsive starter store base storefront cartridge additional B2B functionality cartridge automatic tests for B2B functionality base storefront cartridge base storefront cartridge additional B2B functionality cartridge base storefront cartridge automatic tests for base functionality base storefront cartridge additional B2B functionality cartridge demo content cartridge additional B2B demo content cartridge demo content cartridge demo content cartridge demo content cartridge demo content cartridge development cartridge B2C demo assembly B2X demo assembly micro-services scheduling and recurring orders version file for ICM b2c (Available with ICM 7.9) version file for ICM b2x (Available with ICM 7.9) |
Place the content into the working copy of your project folder (that was generated via CI bootstrap before). Rest assured that there are no conflicting files in your projects folder that otherwise need to be overwritten.
Long path names on Windows
After copying the contents of the a_responsive
Gradle multi-project set into your project folder some files need to be changed to fit your projects configuration.
Replace a_responsive
with your projects name in the following files
// define root project name -rootProject.name = 'a_responsive' +rootProject.name = 'corporateshop'
Replace the com.intershop.responsive
group with your projects group in the following file:
description 'Components Responsive Starter Store Applications' -group = 'com.intershop.responsive' +group = 'com.company.corporateshop' subprojects { - group = 'com.intershop.responsive' + group = 'com.company.corporateshop'
Adapt the release configuration of the project.
// ci configuration - /** - * Intershop release configuration - * requires - * - Sonatype Nexus Pro with a configured staging configuration - * - Atlassian Jira - * and additional environment variables. - * Furthermore an applied SCMVersion plugin is mandatory. - * See https://github.com/IntershopCommunicationsAG/gradle-release-plugins. - **/ - apply plugin: 'com.intershop.gradle.nexuspublish-configuration' - apply plugin: 'com.intershop.gradle.artifactorypublish-configuration' /** * Simple Release configuration * requires only a Maven compatible repository and * additional environment variables. * See also https://github.com/IntershopCommunicationsAG/gradle-release-plugins. **/ - // apply plugin: 'com.intershop.gradle.simplepublish-configuration' + apply plugin: 'com.intershop.gradle.simplepublish-configuration' - /** - * This plugin will create a source package of the build. - * It is possible to use this e.g. for the creation of an ESCROW package. - * _This plugin is optional._ - * See https://github.com/IntershopCommunicationsAG/gradle-release-plugins - **/ - apply plugin: 'com.intershop.gradle.escrow-plugin' - escrow { - sourceGroup = 'com.intershop.public.source' - exclude '*/target' - exclude '**/gradle/wrapper/gradle-wrapper.properties' - } description 'Components Responsive Starter Store Applications' group = 'com.intershop.responsive' assert System.properties['java.version'].startsWith('1.8') - artifactory { - publish { - // for ivy publications - repository { - maven = false - } - // list of publication names - defaults { - publications('ivy', 'ivyEscrow') - } - } - }
Intershop Commerce Management 7.8
Change the Intershop Commerce Management version in the following file:
# dependency versions -version.com.intershop.assembly.commerce_management_b2x = 7.X.0.0 +version.com.intershop.assembly.commerce_management_b2x = 7.X.X.X -version.com.intershop.assembly.commerce_management_b2c = 7.X.X.X
If you need only Intershop Commerce Management B2C use b2c
instead of b2x
:
# dependency versions -version.com.intershop.assembly.commerce_management_b2x = 7.X.0.0 -version.com.intershop.assembly.commerce_management_b2c = 7.X.X.X +version.com.intershop.assembly.commerce_management_b2c = 7.X.X.X
Remove not needed sub projects. Do not skip this step! You really need to delete these folders, otherwise you will run into exceptions.
Assembly Type | Storefront Cartridges | Demo/Init Cartridges | Assembly |
---|---|---|---|
B2C | app_sf_responsive app_sf_responsive_cm app_sf_responsive_b2c app_sf_responsive_smb as_responsive | demo_responsive demo_responsive_catalog demo_responsive_content demo_responsive_search demo_responsive_ocst | inspired-b2c |
B2X | B2C Storefront Cartridges +
app_sf_responsive_b2b app_sf_responsive_costcenter as_responsive_b2b | B2C Demo/Init Cartridges +demo_responsive_b2b | inspired-b2x |
The table gives an overview of the needed cartridges for the different assembly types.
Rename the folder of the assembly sub project 'inspired-b2x'
or 'inspired_b2c'
to your preferred name, e.g., assembly_corporateshop. This name is used for the deployment of the project.
Adapt build configuration for the used assembly
If a B2C assembly will be created:
assert System.properties['java.version'].startsWith('1.8') - def assemblyProjects = [ project(':inspired-b2c'), project(':inspired-b2x') ] + def assemblyProjects = [ project(':assembly_corporateshop') ]
If a B2X assembly will be created:
assert System.properties['java.version'].startsWith('1.8') - def assemblyProjects = [ project(':inspired-b2c'), project(':inspired-b2x') ] + def assemblyProjects = [ project(':assembly_corporateshop') ]
This configuration does only exists in version 3.x (ICM 7.8).
buildDir = new File(projectDir, 'target') - if(name == 'inspired-b2x') { - versioning { - useVersionsFrom 'com.intershop.assembly:commerce_management_b2x' - } - } - if(name == 'inspired-b2c') { + if(name == 'assembly_corporateshop') { versioning { useVersionsFrom 'com.intershop.assembly:commerce_management_b2x' } }
The Responsive Starter Store provides a set of demo cartridges that can be kept as starting point for the projects initialization cartridges or they can be removed completely.
Cartridge | Description |
---|---|
demo_responsive | Demo organization structure for inSPIRED with inTRONICS, inTRONICS Business and Myers |
demo_responsive_catalog | Catalogs with categories and products for the inSPIRED organization |
demo_responsive_content | CMS demo content (including campaigns and promotions) for the inSPIRED organization |
demo_responsive_search | Search demo configuration |
demo_responsive_ocst | Additional demo content of the OCST (Omni-channel Services Toolset, a.k.a. Contact Center) |
demo_responsive_b2b | B2B specific content for the inTRONICS Business channel |
In case they are used as init cartridges it is probably useful to rename the cartridges from "demo_...
" to "init_...
" or some other project naming scheme.
The renaming needs to be done for the cartridges folder name of the cartridge. The display name and description of the cartridge can be renamed in the build.gradle.
The Responsive Starter Store provides a sub-project microservice, which contains the microservices scheduling and recurring order.
Database for microservices
It's mandatory for production system to replace the Derby Database. Therefore the build.gradle of the microservice sub-project has to be adapted
For Oracle it is necessary to configure the correct database driver. If you have this driver in an other group, please adapt the configuration.
dependencies { /** driver for derby */ - runtime 'org.apache.derby:derby:10.12.1.1' /** driver for oracle */ /** this configuration uses the prepared oracle drivers **/ /** see 'Cookbook - Setup CI Infrastructure', 7.2.5 Process for Building the Oracle JDBC Drivers Component **/ + runtime 'com.oracle.jdbc:ojdbc7:12.1.0.2.0.0' }
During the build of same cartridges CSS files will be generated with a Less compiler. These files must be generated to staticfiles/cartridge/static/default/css. Therefore it is necessary to extend the ignore configuration for these cartridges.
Cartridge with less compiler configuration |
---|
app_sf_responsive |
app_sf_responsive_b2b |
app_sf_responsive_smb |
It is possible to add svn:global-ignores
for the project directory:
theme.css theme.css.map
or add svn:ignore
to <cartridge name>/staticfiles/cartridge/static/default/css:
theme.css theme.css.map
Extend .gitignore of the root project:
# IntelliJ project files .idea *.iml out gen *.bak *.log # Eclipse project files **/bin/ **/.settings/ **/.classpath **/.project # editor backup files **~ # Gradle Files **/build/ **/.gradle # Intershop build directories **/target/ # Ignore Gradle GUI config gradle-app.setting # generated css app_sf_responsive*/staticfiles/cartridge/static/default/css/themes.css app_sf_responsive*/staticfiles/cartridge/static/default/css/themes.css.map app_sf_responsive*/staticfiles/cartridge/static/default/css/ # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar
After the changes it is necessary to commit the changes to the used VCS and transfer the files to the remote server.
As mentioned earlier, the demo cartridges of the Responsive Starter Store can be used as blue print for the projects initialization cartridges. For that they should be renamed and fitted to your projects needs.
Regarding the storefront cartridges of the Responsive Starter Store (app_sf_responsive, app_sf_responsive_cm, ...
) there are several options on how you can use and customize them in your projects. Those options are described below.
In any case it might be necessary to not only adapt the app_sf_responsive cartridges but also the application type definitions of as_responsive. If additional project cartridges are added they need to be added to the application type definition too.
This is the above described approach of copying the relevant storefront cartridges of the Responsive Starter Store to your projects.
Any customization can be done within additional project cartridges, with the possibilities overloading and overwriting provides. This is pretty much the same as before, except for the fact that also the Responsive Starter Store storefront cartridges are part of the project cartridges set.
This fact, that the Responsive Starter Store storefront cartridges are part of your projects sources, leads to the second customization option. It is now possible to make any customization directly in the cartridges that were provided by Intershop since they are now project cartridges. You have pretty much the same control over these sources as an Intershop developer has when developing the Responsive Starter Store. Any parts can be changed or removed or added within the cartridges of the Responsive Starter Store. This gives you for example full control over the provided CMS content model, making it possible to simply add new call parameters where needed or removing not wanted components without the need of using the overwrites mechanism.
Using the Responsive Starter Store storefront cartridges as they are is probably the simplest approach. And in case the customization is done within additional project cartridges this is probably the easiest approach for later migrations to new Responsive Starter Store versions too.
In any case newer versions of the Responsive Starter Store cartridges are not getting updated automatically but will be provided as sources too and it is up to the project to decide if and how they will update their currently used Responsive Starter Store cartridges. Less customization in those cartridges will probably make the update/migration easier.
The Responsive Starter Store is intended to be a blue print for a storefront project. The provided cartridges can be used the way they are regarding their naming and their content or they can be customized in any way wanted.
In case you want to create several independent application types that are initially based on the Responsive Starter Store or if you want to create your own storefront cartridge set based on the Responsive Starter Store but with your own naming conventions, you have to copy and rename the app_sf_responsive cartridges to transform them them into your own cartridges.
For this you basically have to search for all references to app_sf_responsive and alike in the Responsive Starter Store cartridges and replace all with your own cartridge naming. This goes for references in the content model files (*.pagelet2), in pipelines, in ISML templates and configuration files.
Also the CMS import files located in sites folder of demo_responsive_content need to be adapted to the new naming.
After this everything should work as before but with the new naming.
In case you want to use or create your own storefront cartridge set that is totally different from the Responsive Starter Store you can also remove the app_sf_responsive cartridges completely from your project. In that case you might only use the configuration files of the Responsive Starter Store but not the cartridges to set up your project.
You would build your storefront only on the basic storefront functionality that is provided by the Commerce Management assembly you are using. Basically this gives you only the storefront functionality of the sld_ch_sf_base cartridge. The whole storefront view layer would need to be provided by your own cartridges.
Internally, Intershop uses an release process with staging for releases, so that unused milestone builds can be easily dropped. For reporting purposes all issues will be extended with the solved version during the build process. Furthermore the version of internal Intershop projects is calculated from used source repository (see https://github.com/IntershopCommunicationsAG/scmversion-gradle-plugin.) This plugin is required by the release plugin com.intershop.gradle.nexuspublish-configuration. It is also possible to use a version in a property file. In this case the configuration for the com.intershop.gradle.scmversion plugin can be removed.
During the build of same cartridges CSS files will be generated with a less compiler. It is necessary, that these files must be generated to staticfiles/cartridge/static/default/css. Therefore it is necessary to extend the ignore configuration for these directories.
I want to run the deployment.
To deploy an assembly execute the following steps:
The workflow for initial installation, upgrade, downgrade is always the same.
The only difference is the used assembly (version) in your settings.gradle file. The deployment automatically handles if there is already a version available in the target directory and deploys the difference.
The deployment will not create any users on your target system. Therefore, you have to create a user. This users can execute the deployed system. It is the same user that can run the deployed application.
If you want to run different applications like the webserver and the application server on different hosts, you have to run multiple deployments from multiple settings.gradle files.
User name and groups can be chosen freely.
The user name and group must be declared in the settings.gradle file, see Recipe: Configure the Deployment. This allows for a validation that the current user intends to run the deployment. Also the user will run the Windows services.
To execute the deployment:
Execute the following command:
<gradle command> deploy
There are some operations which require root/administrator privileges. For those operations, the deployment creates a post install script. The post install script(s) are listed at the end of the deployment:
------------------------------------------------------------------------------------ To finish the deployment please execute the following scripts as administrator / with root privileges: /folder/postInstall/installServices.sh ------------------------------------------------------------------------------------
Gradle does not support writing log output to a file. Use console redirection or the Linux tee
command. See also Gradle user guide on Logging (2.11, 2.7, 2.3, 2.0, 1.8).
I want to run the deployment.
To deploy an assembly execute the following steps:
The workflow for initial installation, upgrade, downgrade is always the same.
The only difference is the used assembly (version) in your settings.gradle file. The deployment automatically handles if there is already a version available in the target directory and deploys the difference.
The deployment will not create any users on your target system. Therefore, you have to create a user. This users can execute the deployed system. It is the same user that can run the deployed application.
If you want to run different applications like the webserver and the application server on different hosts, you have to run multiple deployments from multiple settings.gradle files.
User name and groups can be chosen freely.
The user name and group must be declared in the settings.gradle file, see Recipe: Configure the Deployment. This allows for a validation that the current user intends to run the deployment. Also the user will run the Windows services.
To execute the deployment:
Execute the following command:
<gradle command> deploy
There are some operations which require root/administrator privileges. For those operations, the deployment creates a post install script. The post install script(s) are listed at the end of the deployment:
------------------------------------------------------------------------------------ To finish the deployment please execute the following scripts as administrator / with root privileges: /folder/postInstall/installServices.sh ------------------------------------------------------------------------------------
Gradle does not support writing log output to a file. Use console redirection or the Linux tee
command. See also Gradle user guide on Logging (2.11, 2.7, 2.3, 2.0, 1.8).
Since Gradle Tools Version >= 2.1.
I want to get more information about my deployed instance.
The Gradle task listing
will create a file listing.txt containing information about all the deployed resources and their current state.
The resulting output file may be quite large, therefore mind some hints:
grep
) to get only the information you are looking for.The general syntax for each entry is as follows:
Flags ResourceName [AdditionalInformation]
svn status
:M
modified!
missing?
unknown (file has not been created by the deployment)~
different type (e.g., there is a directory instead of a file)(:project:taskName)
the task that deployed this resource. (Only if the state flag does not indicate unknown)
On Windows starting one of the services fails. There are (at least) two kinds of problems here:
Log on failure. The according error message is:
Windows could not start the <service name> service on Local Computer. Error 1069: The service did not start due to a logon failure.
Service-specific failure. The according message is:
Windows could not start the <service> on Local Computer. For more information, review the System Event Log. If this is a non-Microsoft service, contact the service vendor, and refer to the service-specific error code <error code>.
Typical problems causing this message are:
In both cases the following procedure solves the problem:
The most typical reason for a service-specific failure (after an otherwise successful deployment) is that local ports are blocked by other applications. To verify this:
The service may file multiple of such errors. The Intershop HTTP Server service reports a blocked port like this:
The Apache service named <service> reported the following error: >>> (OS 10013)An attempt was made to access a socket in a way forbidden by its access permissions. : AH00072: make_sock: could not bind to address [::]:<port> .
To find out which application blocks the port, run the following command on the command line:
netstat -aon | find ":<port>"
The last column of the output is the process ID (which you can connect to a process name in the Task Manager).
How to change a file based configuration of Intershop 7 as an administrator/developer, i.e., overwriting the default if any?
Examples are:
First of all the solution depends on the operational concept:
This is straight-forward, but has a few disadvantages (see the discussion). For this approach see the recipe Keep Local Modifications to keep the deployment from restoring the originally deployed content of configuration files.
There a few cases here:
The administrator's effort for automatically changing configuration can reduced and moved to the developer. See the Recipe: Provide Custom Deployment Configuration and Logic.
For the special use case of changing the configuration, the following divisions of work are thinkable:
Editing configuration files manually after deployment is the easiest solution for disposable or low-frequency deployments. Its big disadvantage is that it cannot be repeated easily and does not help you in monitoring configuration and restoring from broken states. This is against the ideas of continuous delivery/devops, but still possible.
If you use this approach, you must configure the deployment to keep your modified versions of deployed files. The default behavior is to restore the originals on every deployment run. See the the Recipe: Keep Local Modifications.
Note
Changes introduced through the development will not make it into these files anymore, essentially omitting them from upgrades.
Most configuration of Intershop 7 is read through the configuration framework in forms of properties. If you want to change these properties, provide your values in an additional configuration source and make it have priority over other sources. Configuration sources and their priorities are configured in <IS_SHARE>/system/config/cluster/configuration.xml.
One kind of configuration source are properties- files. The default configuration.xml file declares to load <IS_SHARE>/system/config/cluster/<environment>.properties if it exists. Its priority is higher than most of the properties-files in <IS_SHARE>/system/config/cluster, like appserver.properties or orm.properties. The name of the file must match the environment you specify in your settings.gradle, e.g., <IS_SHARE>/system/config/cluster/production.properties for environment 'production'.
To add additional configuration sources, you may use the XmlContentFilter
, see section XmlContentFilter of the Recipe: Change Deployed File Content Through Filters.
Recipe: Provide Custom Deployment Configuration and Logic
Where to declare deployment configuration and custom logic?
Provide deployment configuration and logic by settings properties/calling methods on a Gradle Project
object and the DSL extensions attached to it. Developers and administrators can do so in different places. As described in the Concept - Gradle Deployment Tools, there is a hierarchy of Project
objects. The root Project
represents the assembly itself, while all child Project
objects represent components included in the assembly.
Code snippets in this cookbook, unless stated otherwise, can be put in any of these locations:
As an administrator use the deploymentBootstrap
.config
block inside the settings.gradle file of the deployment.
... deploymentBootstrap { ... config { // configure the root project here // for configuring child projects, see discussion } }
As a developer use the deployment/deploy.gradle file of your custom components for configuration and deployment that your component requires.
Note
The behaviour of the deployment changes depending on whether a deploy.gradle script is provided or not. When you do not provide a deploy.gradle, the CartridgeDeploymentPlugin
is applied by default.
If you do provide a deploy.gradle, only its content will configure deployment for the according component. If you want to retain the previous behaviour, you have to include the following snippet into your deploy.gradle:
apply plugin: com.intershop.deploy.cartridge.CartridgeDeploymentPlugin
As a developer use the deploy.gradle file of your assembly for configuration that cannot be associated to a single component or that is only required in the deployment of that assembly, instead of all assemblies that might include that single component. See the Recipe: Add Custom Deployment Logic to an Assembly or Recipe: Add Custom Deployment Logic to an Assembly (valid to 7.8), depending on your version, for details.
Some pieces of deployment data are only known by the administrator at deployment time (like paths and ports). The deployment logic/configuration provided by the developer can read these pieces of data from logic/configuration provided by the administrator in the following ways:
Project
properties for simple data types and small amounts of data.See also chapter Multi-project Builds in the Gradle User Manual (2.11, 2.7, 2.3, 2.0, 1.8).
Each of the above mentioned locations by default configures a certain Project
. The following listings describe that default Project
object and show how to configure other Project
objects.
Gradle projects are always accessed by their path. The path of the root project is the colon ':', the path of other projects is a colon followed by the (unqualified) name of the associated component: :<component name>
, e.g., :bc_foundation
.
The use of Gradle's afterEvaluate
is explained in the next section.
... deploymentBootstrap { ... config { // configure the root project here // To configure a child project: if (findProject(':<component name>')) { project(':<component name>') { afterEvaluate { // configure the child project here } } } } }
For developer deployments (for which settings.gradle is generated and not subject to manual editing) add a Gradle init script:
settingsEvaluated { Settings settings -> if (!settings.extensions.findByName('deploymentBootstrap')) { // Not a deployment return; } settings.deploymentBootstrap { config { logger.lifecycle('Applying custom deployment configuration from: ' + initscript.sourceFile) //Write any configuration that can be specified // in the config-Block of the settings.gradle // this is like appending it to the actual settings.gradle // (i.e. it will be executed after the config block of the settings.gradle) } } }
// configure the root project here // To configure a child project: if (findProject(':<component name>') { project(':<component name>') { afterEvaluate { // configure the child project here } } }
For Gradle tools version 1.0 - 1.1:
// configure the project associated with the component here // To configure another child project: if (findProject(':<component name>')) { project(':<component name>') { def configClosure = { // configure the other child project here } if (project.state.executed) { configClosure() } else { afterEvaluate(configClosure) } } } // To configure the root project: project(':') { // configure the root project here }
For Gradle tools version >= 2.0:
Each project has the method evaluatedProject
to which you pass in a closure. If the project is already evaluted the closure will be executed immediately. Otherwise it will be executed one the project has been evaluated. This makes configuring other projects easier:
// configure the project associated with the component here // To configure another child project: if (findProject(':<component name>')) { project(':<component name>').evaluatedProject { // configure the other child project here } } // To configure the root project: project(':') { // configure the root project here }
Defensive Project Access
The listings above defensively access child projects, i.e., they first check if a certain project exists before trying to configure it. This is best practice for at least two reasons:
When providing custom deployment configuration/logic in different locations the order of their evaluation is critical. Deployment configuration is mostly a three-step process distributed over different locations:
For example:
TargetPlugin,
which defines adds an extension target
to the project for configuration the location of IS_HOME and IS_SHARE.localDirectory
and targetDirectory
of the target
extension.target.localDirectory
to determine where to deploy its start scripts.The following diagram shows the different locations and the order in which they are evaluated:
settings.gradle ... deploymentBootstrap { ... config { // Evaluation-Order: #2 // configure the root project here // To configure a child project: if (findProject(':<component name>') { project(':<component name>') { afterEvaluate { // Evaluation-Order: #5 // configure the child project here } } } } } | deploy.gradle of the assembly // Evaluation-Order: #1 // configure the root project here // To configure a child project: if (findProject(':<component name>') { project(':<component name>') { afterEvaluate { // Evaluation-Order: #5 // configure the child project here } } } | deploy.gradle of a component // deploy.gradle script of any component // Evaluation-Order: #3 // configure the project associated with the component here // To configure the root project: project(':') { // Evaluation-Order: #4 // configure the root project here } // To configure another child project: if (findProject(':<component name>')) { project(':<component name>') { def configClosure = { // Evaluation-Order: #5 // configure the other child project here } if (project.state.executed) { configClosure() } else { afterEvaluate(configClosure) } } } |
The order between multiple locations with the same number is not determined. Do not rely on the order and make sure that different orders do not cause different behavior. Examples of this are:
project.state
first in the listing.)afterEvaluate
blocks applied to the same project.Late Evaluation of extension 'deployment'
A very important DSL extension is the ResourceDeploymentExtension
attached to the property deployment
of the project. It is used to deploy files, links, directories, apply content filters and create services. It is configured using the method deployment
, which expects a closure. Closures passed to the deployment
method are evaluated late, so they can access data specified in the settings.gradle, like the target.shareDirectory
.
deployment { // Configure the ResourceDeploymentExtension here // Evaluation-Order: #5 (like all afterEvaluate closures) // This example adds an additional property file files { additionalProperties { from new File('/etc/config/intershop7/additional.properties') // Define target of the copy operation into new File(target.shareDirectory, 'system/config/cluster/') } } }
Use extra project properties to pass in data from the settings.gradle file to deployment logic/configuration provided by development. See also Gradle DSL documentation on Project
(2.11, 2.7, 2.3, 2.0, 1.8). Extra project properties can be any Java object of any type. Especially, use File
, List
or Map
if applicable.
The following listings show how to use an extra property across the deploy.gradle file of the assembly, provided by the developer, and the settings.gradle, provided by the administrator.
deploy.gradle of assembly ... //1. Create the extra property and set a default value (you can use null if there is none) project.ext.additionalPropertiesFilesDir = new File('/etc/config/intershop7') deployment { //3. Use the value in a location evaluated settings.gradle files { additionalProperties { from new File(project.additionalPropertiesFilesDir, 'additional.properties') into new File(target.shareDirectory, 'system/config/cluster/') } } } | settings.gradle ... deploymentBootstrap { ... configure { //2. Provide a value additionalPropertiesFileDir = new File('/opt/intershop7/config') } } |
How can I deploy a different content for a file than the content that was delivered by the development/build process?
Examples are:
Use configuration framework if possible
Modifying file contents through filters is a low-level operation. Please check the Recipe: Configure Intershop 7 on whether a higher level and easier approach is available first.
For example most properties-files like <IS_SHARE>/system/config/cluster/appserver.properties or orm.properties are read by the configuration framework. To override their values rather provide a <IS_SHARE>/system/config/cluster/<environment>.properties file as described in the above recipe.
Declare a content filter. You must specify:
This discussion initially describes everything that is independent of the filter type. After that comes a section for each built-in filter type. It is also possible to apply custom content filters, see Recipe - Apply a Custom Content Filter.
Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
The general skeleton for filters looks like this:
deployment { ... filters { <type dependent creation method>('<name>') { dir = <Java File object> include '<Ant style pattern>' exclude '<Ant style pattern>' ... } } }
You may define an arbitrary number of includes and excludes. Includes and excludes can be provided by:
dir
,File
object and returning true
or false
(the represented file may not exist yet, for initial deployments).A file is affected by a filter if:
dir
andThe following example applies a filter to all pagelet-files inside <IS_SHARE>/sites or any nested directory, except for files ending in a digit:
deployment { ... filters { <type dependent creation method>('<name>') { dir = target.shareDirectory include 'sites/**/*.pagelet' exclude { file -> file.path.matches /\d$/ } ... } } }
Things to keep in mind
Filters are applied based on the destination of a deployed file. It does not matter where the file was deployed from. This is especially useful, if you replace a deployed file by a different one, as done in custom fixes or patches. For example a patched shell/batch script will still have the placeholders in it replaced during deployment.
Multiple filters may be applied to the same file. The content is passed through them in a chain. The order in this chain is undetermined and should not influence the outcome.
Filters will have no effect on files that are matched by dir
, include and exclude, but are not created by the deployment.
Use an OverridePropertiesFilter
to specify property values in in properties-files. If the property exists, the filter overwrites its value, otherwise creates a new entry.
Create the filter using the method overrideProperties
. Fill the map properties
with all properties you want to create over overwrite.
The following example overwrites two values in <IS_HOME>/webadapter/webadapter.properties.
deployment { ... filters { overrideProperties('customizePageCache') { dir = target.localDirectory include 'webadapter/webadapter.properties' properties['errorlog.level'] = 'INFO' properties['webadapterAgent.pageCache.expiredFiles.deletionDelay'] = 60 } } }
Use an XmlContentFilter
to modify xml-files. Create the filter using the method xmlContent
. Specify how to modify the content by passing a closure to the method withXml
. The filter passes in an XmlProvider
to the closure, which can be used to read and modify the files contents.
For details on XmlProvider
see Gradle API (1.8, 2.1, 2.3, 2.7, 2.11).
The following example adds a set
element in <IS_SHARE>/system/config/cluster/configuration.xml after the last set
element with a scope
attribute of "domain". This snippet is useful for adding your own configuration sources to the configuration framework.
deployment { ... filters { xmlContent('addPropertiesFileToConfigurationFramework') { dir = target.shareDirectory include 'system/config/cluster/configuration.xml' withXml { XmlProvider provider -> def sets = provider.asNode().sets.first().children() def lastDomainSpecificSet = sets.findAll {it.@scope=='domain'}.last() def newSet = new Node(null, 'set', [finder:'property', scope:'cluster,server,domain', fileName:'/etc/config/intershop7.properties']) sets.add(sets.indexOf(lastDomainSpecificSet)+1, newSet) } } } }
Use a PlaceholderReplacementFilter
if a file contains placeholders that need to be filled by the deployment. The filter will treat all substrings of the file that start and end with specific tokens as a placeholder and take the string in between for its name. (Placeholders never span across lines.)
Create the filter using the method replacePlaceholders
. Fill the map placeholders
with all placeholders you want to provide values for. Optionally specify the start and end token in the properties beginToken
and endToken
, defaults are '<@' and '@>'.
The following example replaces all occurences of '<@IS.HOME@>' and '<@IS.SHARE@>' by their location in all shell scripts inside <IS_HOME>/bin.
deployment { ... filters { replacePlaceholders('placeholders') { dir = target.localDirectory include 'bin/*.sh' placeholders['IS.HOME'] = target.localDirectory placeholders['IS.SHARE'] = target.shareDirectory } } }
Use an EditLinesFilter
to modify files on a line-by-line basis. Create the filter using the method editLines
. Specify how to modify the content by passing a closure to the method action
. The filter calls the closure for each line of the file passing in the line as a String. Yield the modified line as return value of your closure.
The following example sets the ServerAdmin
directive in the file <IS_HOME>/httpd/conf/httpd.conf.
deployment { ... filters { editLines('provideAdminEmail') { dir = target.localDirectory include 'httpd/conf/httpd.conf' action { String line -> line =~ /^\w*ServerAdmin/ ? 'ServerAdmin admin@customer.com' : line } } } }
(Available since Gradle tools version 1.1)
Use a FullContentFilter
to gain full access to a files content and modify it arbitrarily. Use it only for text files and files that have reasonable sizes, since the full file content will be loaded into memory at once.
Create the filter using the method fullContent
. Specify how to modify the content by passing a closure to the method action
. The filter calls the closure passing in a StringBuilder
. Modify the content by calling methods of this StringBuilder
inside the closure.
The following example appends an Include
-directive to the file <IS_HOME>/httpd/conf/httpd.conf.
deployment { ... filters { fullContent ('appendHTTPDConfInclude') { dir = target.localDirectory include 'httpd/conf/httpd.conf' action { StringBuilder content -> /* * append: * # MyModule configuration * Include ${target.localDirectory}/etc/httpd/extra/my-module.conf */ content.append(System.lineSeparator + '# MyModule configuration' + System.lineSeparator + "Include ${target.localDirectory}/etc/httpd/extra/my-module.conf") } } } }
How to deploy files not covered by the default deployment routines?
For the deployment of files you have to configure a Gradle CopySpec
, see Gradle API (2.11, 2.7, 2.3, 2.1, 1.8); also see the corresponding Gradle user guide on Working With Files (2.11, 2.7, 2.3, 2.1, 1.8). You may use this to copy a single file, multiple files or extract files from an archive.
Doing this through the deployment, instead of using simple copy commands, will give you all the advantages of our indexed deployment, e.g., collision detection, modification handling and automatic undeployment.
Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
To deploy files from your source project, those files must be published to the binary repository as standalone Ivy artifact or included in a *.zip file. For further details refer to Cookbook - Gradle Build Tools.
You can then refer to the repository's artifacts in your deployment logic.
deployment { files { example { // Unzip source artifact 'foo' from artifacts(type:'foo', extract: true) // Select subset to be deployed here include '**/*.properties' // Define target of the copy operation into new File(target.shareDirectory, 'system/config/cluster/') } } }
You can also deploy files directly from the local file system.
deployment { files { productionProperties { // Copy a single file from the same folder as this settings.gradle file from new File(settingsDir, 'production.properties') // Define target of the copy operation into new File(target.shareDirectory, 'system/config/cluster/') } } }
I have an artifact in which I need to replace some parts according to the environment. The predefined filters do not fit for my scenario.
To solve this problems execute the following steps:
The solution starts with implementing your own filter. The best starting point is the com.intershop.deploy.filters.AbstractDeploymentContentFilter
. You only need to implement your filter logic on top of this class.
An easy example for a filter replacement is replacing all placeholders in a string with another value.
package com.intershop.deploy.filters; import org.gradle.api.file.ContentFilterable class ReplaceAllFilter extends AbstractDeploymentContentFilter { Map<String, String> placeholders = [:] ReplaceAllFilter(String name) { super(name) } @Override public void configureNormalizedFilter(ContentFilterable filterable) { filterable.filter { String line -> placeholders.each {String key, value -> line = line.replace(key, value) } line } } }
To register your filter, add the following line to your deploy.gradle script.
import com.intershop.deploy.filters.ReplaceAllFilter deployment { filters { registerBinding(ReplaceAllFilter, ReplaceAllFilter) } }
To configure your filter, add the following lines to your deploy.gradle script.
The configuration varies according to your filter.
import com.intershop.deploy.filters.ReplaceAllFilter deployment { filters { registerBinding(ReplaceAllFilter, ReplaceAllFilter) replaceAll(ReplaceAllFilter) { dir = infrastructureDeployment.localDirectory include 'httpd/conf/httpd.conf' placeholders['ServerAdmin admin@localhost'] = 'ServerAdmin admin@intershop.com' } } }
I need to customize the deployment of an archive. This includes renaming of files, exclusion of files or deployment of some files to another target directory.
Use a FileDeployment, which is a Gradle CopySpec for configuring the deployment.
Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
The following example shows how to configure the deployment.
It deploys the init.d files by changing the name to the directory etc/init.d.
deployment { files { initd { from artifacts(type:'local', extract: true) // Include files in this processing include 'etc/init.d/eserverx*' // Rename files rename { String fileName -> fileName.replace('eserverx', "eserver${project.instanceId}") } // Change target directory into new File(infrastructureDeployment.localDirectory, 'etc/init.d') } } }
I need to create a directory during deployment.
Parent directories are created automatically when deploying files. There is no need for any action in this case.
To create a directory without deploying files inside,
Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
The following example shows a sample configuration.
deployment { directories { if (target.includeLocal) { localLog { path new File(target.localDirectory, 'log') } } if (target.includeShare) { shareLog { path new File(target.shareDirectory, 'system/log') } } } }
This will create the directories IS_HOME/log and IS_SHARE/system/log regardless of whether or not files will be deployed into these directories.
A directory, that has not been defined as directory resource, will get deleted once its last entry is removed.
However, for directories that are defined as directory resource, the following applies:
I want to create a custom symbolic link at my target system.
Configure the deploy.gradle script of your component to create the link. Links are currently only supported at linux platform.
For the creation of the link define:
Attribute | Description |
---|---|
from | the location of the link |
to | the target the symbolic link points to |
Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
The following example shows a sample configuration.
deployment { links { varPublic { from = new File(project.instanceVarDir, 'webadapter/public') to = new File(target.localDirectory, 'webadapter/public') } varLog { from = new File(project.instanceVarDir, 'log/webadapter') to = new File(target.localDirectory, 'webadapter/log') } etcDir { from = new File(project.instanceEtcDir, 'webadapter.properties') to = new File(target.localDirectory, 'webadapter/webadapter.properties') } } }
I want to add a custom service.
For creating a service do the following:
The creation of services differs for Linux and Windows systems. By that reason you need to decide, for which platform you want to create a service. If you need to support both platforms, you need to add two configurations to your deployment script.
To configure a service for Linux you need to set the following attributes at your service definition.
Attribute | Description |
---|---|
serviceScript | init.d script of the service |
runLevels | Run levels for the service (keep empty for no runlevel) |
Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
The following example shows, how to configure a service for Linux.
deployment { services { linux { webAdapter { serviceScript = new File(target.localDirectory, "etc/init.d/eserver${target.instanceId}-httpd") runLevels = [3,5] } } } }
To configure a service for Windows you need to set the following attributes at your service definition.
Attribute | Description |
---|---|
serviceName | Name of your service (ID) |
command | Command to execute the service |
displayName | Name of the service which is displayed to the user |
startupType | Type of startup configuration
|
user | User the service should be executed with |
The following example shows, how to configure a service for Windows.
deployment { services { windows { webAdapter { serviceName = 'Service 1' command = [ new File(target.localDirectory, 'httpd/bin/httpd.exe').absolutePath, '-k', 'runservice', '-n', serviceName, '-f', new File(target.localDirectory, 'httpd/conf/httpd.conf').absolutePath] displayName = 'INTERSHOP HTTP Server' startupType = com.intershop.deploy.resources.WindowsServiceDeployment.StartupType.AUTOMATIC user = assemblyDeployment.user } } } }
Because you must be administrator to install services, the deployment will not automatically create the new service during deployment. The result of the deployment will be a postinstall script which must be executed by an administrator.
Since Gradle tools version >= 2.0.
I need to deploy an additional *.war file into the servlet container.
The Tomcat servlet container of Intershop 7 can be used to host any *.war file and is not limited to the Intershop application.
Gradle Deployment Tools 2.0 introduced a new extensible API for Tomcat server instances. You have to
tcm
, 3rd_tomcat
and runtime
), see Cookbook - Gradle Assembly Tools or Cookbook - Gradle Assembly Tools (valid to 7.8), depending on your version. Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
The following snippet shows the structure of the Tomcat DSL.
tomcat { instances { instanceName { // insert server-specific configuration here } } }
Specify a given tomcat instance to host your custom web app. For this purpose each Tomcat instance object is ExtensionAware
, see Gradle API (2.11, 2.7, 2.3, 2.1, 2.0) and can be customized via extensions. There are several possibilities to leverage this functionality:
In cases where your custom web app does not need custom configuration, you can just attach a named flag to the Tomcat instance:
ext.myExt = true
This code will create an additional flag named myExt
, that just marks the Tomcat instance for your deployment script.
When you need additional configuration properties for your web app, it is recommended to use a JavaBean-compliant class for your extension:
extensions.create('myExt', MyExtClass) myExt { foo = 'bar' }
This code will create an extension named myExt
with a new instance of class MyExtClass
. Then you can configure your extension the usual Gradle-way.
In case you want to avoid creating your own extension class, you can also use a dynamic Groovy object instead:
extensions.add('myExt', new Expando()) myExt { foo = 'bar' }
This code will create an extension named myExt
with a new dynamic Groovy Expando
, that you can assign any kind of properties. You can also configure this extension the usual Gradle-way.
Alter your component's deployment script to deploy its web app into those servers, that have been configured accordingly:
apply plugin: com.intershop.deploy.assembly.TargetPlugin apply plugin: com.intershop.deploy.intershop.TomcatPlugin deployment { if (target.includeLocal) { files { tomcat.instances.find { it.hasProperty('myExt') }.each { instance -> "${instance.name}Tomcat" { from artifacts(type:'webapp', extract: true) into instance.baseDir } } } } }
The instance's baseDir
refers to the specific Tomcat CATALINA_BASE directory.
How to replace an file which was deployed by another component?
The typical use case for this is providing a patch for a component.
Replacing a file is a drastic measure. Consider using content filters to alter an existing file instead of providing your own version, because it eases future migrations.
Use the configuration framework/deployment filters if possible
Replacing a whole file is a low-level and very drastic operation. Please check the Recipe: Configure Intershop 7 on whether a higher level and easier approach is available first.
For example most properties-files like <IS_SHARE>/system/config/cluster/appserver.properties or orm.properties are read by the configuration framework. To override their values rather provide a <IS_SHARE>/system/config/cluster/<environment>.properties file as described in the above recipe.
To solve this problem execute the following steps:
If you configured the deployment of your custom file correctly, the deployment will abort with a DuplicateResourceException
like this:
FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':<component 1>:deploy<deployment name 1>Files'. > Task :<component 1>:deploy<deployment name 1>Files: Resource '<file>' already defined for Task :<component 2>:deploy<deployment name 2>Files
One of the task names belongs to your component and your FileDeployment
declaration. (For the assembly the name of the component will be missing.) Fill in the other component and deployment name.
FileDeployment
implements a standard Gradle CopySpec
, see Gradle API (2.11, 2.7, 2.3, 2.1, 1.8). To exclude the original add the following deployment configuration:
Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
Order of evaluation
Since the code below configures one project from the script of another/the root project/the settings.gradle, the order of evaluation of the scripts must be considered. Please see the Recipe: Provide Custom Deployment Configuration and Logic for more detailed information on how to do this.
if (rootProject.findProject(':<component>')) { rootProject.project(':<component>') { afterEvaluate { deployment.files.<deployment name> { exclude { new File(destinationDir, it.path) == <file object pointing to the deployed file>) } } } } }
The following example shows how to replace the <IS_SHARE>/system/config/oracle/tnsnames.ora file deployed by component core
.
Deploy a custom version:
deployment { files { tnsNamesOra { // Copy a tnsnames.ora file from the same folder as this settings.gradle file from new File(settingsDir, 'tnsnames.ora') // Define target of the copy operation into new File(target.shareDirectory, 'system/config/oracle/') } } }
The conflict message shown during deployment:
FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':core:deployShareFiles'. > Task :core:deployShareFiles: Resource '...\system\config\oracle\tnsnames.ora' already defined for Task :deployTnsNamesOraFiles
Exclude original file:
Since Gradle Tools 2.0:
project(':core') { afterEvaluate { deployment.files.share { exclude { new File(destinationDir, it.path) == new File(target.shareDirectory, 'system/config/oracle/tnsnames.ora') } } } }
For Gradle Tools 1.0 and 1.1:
if (findProject(':core')) { project(':core') { def configClosure = { deployment.files.share { exclude { new File(destinationDir, it.path) == new File(target.shareDirectory, 'system/config/oracle/tnsnames.ora') } } } if (project.state.executed) { configClosure() } else { afterEvaluate(configClosure) } } }
I want to customize the strategy, how the deployment proceeds when it detects external modifications on deployed resources.
Modification handling can be configured on two levels:
Regardless of the way of configuration, there are four modification handling strategies available:
Strategy name | Behaviour |
---|---|
overwrite | always overwrites local modifications and causes a warning |
keep | always keeps local modifications, thereby skips deployment of this resource, and causes a warning |
abort | aborts the deployment process in case of a conflict without altering locally modified resources |
backup | renames the existing file by appending -backup or -backup1, -backup2 etc to avoid conflicts |
You must assign a priority to each modification handling specification. A priority is just a string and its rank is defined by a list, that names all available priorities in ascending order. Please, consider the priorities ['default', 'intershop']
, in which case intershop
has a higher priority than default
. These priorities allow for fine-grained control over which modification handling strategy is to be used for any given file. There are two priorities defined per default:
default
is the priority of the global fallback strategy, see belowintershop
is the priority of all file-specific modification handling specifications, that are predefined in standard IS7.Customer projects are encouraged to use an own priority level, to be able to override both default
and intershop
specifications.
Avoid Conflicts!
Modification handling specifications must not be ambiguous! If two handlers apply to the same file, they must differ in their priority levels, in which case the higher priority specification wins.
Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
The global fallback modification handling strategy is configured as a property in the deployment DSL, as is the order of handling priorities:
assemblyDeployment { //... defaultModificationHandler = 'abort' modificationPriorities = ['default', 'intershop', 'myProject'] }
Components can declare how their deployed components are to be handled in case of an external modification. Modification specification via includes/excludes works just like it does for filters:
deployment { modification { backup('intershopProperties') { priority 'myProject' dir target.localDirectory include 'intershop.properties' } } }
I want to deploy systems that participate in a data replication environment.
Setting up a simple two-node data replication environment involves the following major tasks:
The data replication deployment involves at least one source cluster and one target cluster. The number of IAS and IWS instances and their distribution is irrelevant to the data replication mechanism. This recipe illustrates a simple two-node data replication deployment, which includes two single-host Intershop 7 clusters (using the host type all).
The following sections assume that the deployment preconditions (as described in Recipe: Prepare the Deployment) are met, i.e., that the Intershop 7 users, the deployment target directories etc are prepared on both nodes.
When setting up a data replication environment, you must first deploy the target (live) cluster in order to get a replication configuration file, which must be copied and modified for deploying the source (editing) cluster later.
To deploy the target cluster, follow the proceedings as described in Recipe: Configure the Deployment. The config DSL block of the settings.gradle file, however, needs some additional information:
config { ... database { host = '<db-hostname>' port = <db-port> serviceName = '<db-servicename>' tnsAlias = '<db-tnsalias>' user = '<live-db-user>' password = '<live-db-password>' oracleClientDir = new File('</opt/oracle/client|c:/oracle/client>') } staging { systemType = 'live' } }
For more details, see Recipe: Configure Mass Data Replication.
The source (editing) cluster needs a specific data replication configuration, which tells it the required details of the target (live) cluster. To prepare the source cluster configuration:
Copy the example replication configuration file to the deployment directory of the source (editing) cluster host.
This file, replication-clusters.xml.sample, is located in /opt/intershop/eserver1/share/system/config/cluster of the deployed target (live) cluster.
Open the copied replication configuration file and edit the settings as required.
The following parameters must be set:
Parameter | Description/Example |
---|---|
Target system, ID and activity | <target-system id="TargetSystem" active="true"> |
Web server URL | <webserver-url>http://target(live)-system-host:port</webserver-url> |
Database source/target communication | Use either a database link or, if the source and target system databases reside in the same database instance, a direct schema access. Database link: Target schema name for direct schema access: |
To deploy the source cluster, follow the proceedings as described in Recipe: Configure the Deployment. As with the deployment of the target cluster, the config DSL block of the settings.gradle file needs additional information:
config { ... database { host = '<db-hostname>' port = <db-port> serviceName = '<db-servicename>' tnsAlias = '<db-tnsalias>' user = '<edit-db-user>' password = '<edit-db-password>' oracleClientDir = new File('</opt/oracle/client|c:/oracle/client>') } staging { systemType = 'editing' replicationClustersFile = new File('</opt/intershop/install/replication-clusters.xml|c:/install/replication-clusters.xml>') } }
Preparing data replication environments involves additional post-deployment tasks:
Intershop recommends to recheck the configuration files for the data replication after the clusters' deployment. In both the target cluster and the source cluster, the corresponding files staging.properties and replication-clusters.xml are located in <eserver#>/share/system/config/cluster.
Make sure that the following details are properly set:
staging.properties
Provides basic settings like the system role (editing, live) for the current Intershop 7 cluster, must be configured in both clusters (source and target).
In the source cluster, the staging type setting must be
staging.system.type = editing
In the target cluster, the staging type setting must be
staging.system.type = live
replication-clusters.xml
Provides the communication setting for a source cluster to connect to the target cluster(s) via database link or database schema access, must be configured in the source cluster.
When using a database link between two database instances, the target-system
section must include a line like
<source-database-link>ISEDITING</source-database-link>
When directly accessing a database schema within one database instance, the target-system
section must include a line like
<target-database-user>INTERSHOP_LIVE</target-database-user>
The data replication mechanism is based on a set of specific tables (live and shadow tables), which need to be created before the actual data replication can take place. This requires to initialize the database accordingly. Two basic approaches are available to initialize the database in a new replication environment:
Running a DBinit process on the source (editing) cluster, then exporting a database dump and importing this dump in the target (live) cluster
With this approach, you can already prepare the required database tables when executing the DBinit process. For information about DBinit, refer to Cookbook - DBInit.
Importing an existing database dump in both the source (editing) and the target (live) clusters
With this approach, the database tables required for the data replication are created during the first replication process. For information about data replication, the involved procedures, its initialization etc, refer to Cookbook - Mass Data Replication - Administration.
A database link is a probable option to provide for the communication between the source cluster and the target cluster. If you chose to use a database link, you must create it in the database schema of the target cluster. To do so, log on to the target cluster as the live database user <live-db-user>
and issue the following SQL commands (replacing the placeholders).
To remove an old database link, execute
DROP DATABASE LINK isediting;
To create a new database link using, for example, the easy connect syntax, execute
CREATE DATABASE LINK isediting CONNECT TO <edit-db-user> IDENTIFIED BY <edit-db-password> USING '//<edit-db-hostname>:<edit-db-port>/<service_name>';
To test the database link, execute
SELECT tname FROM tab@isediting;
How to undeploy the whole assembly?
There is a dedicated Gradle task to undeploy all artifacts of the installed assembly. This task undeploys all artifacts, that have been registered in the index file during previous deployment operations. The handling of artifacts, that have not been indexed, can be configured.
Undeployment during upgrade
Installing a new assembly (version) automatically removes obsolete files from previous deployments.
To start the undeployment:
Execute the following command as the user, who originally deployed the assembly.
<gradle command> undeploy
Note
Running Services
You cannot remove the server's artifacts, as long as its services are still running. In this case proceed as follows:
Undeploy the services.
<gradle command> undeployServices
Undeploy the rest of the assembly.
<gradle command> undeploy
Additional files are placed into the installation directories by the running server, e.g., log files or page compile artifacts. As those files are not registered in the index, undeployment cannot associate those files with installed components.
You can configure whether or not those artifacts are to be deleted in your local installation's settings file:
Use Code Examples
The code examples provided in this recipe can be copied to the deploymentBootstrap.config
block of the settings.gradle at deployment time.
... deploymentBootstrap { ... config { // Insert code examples here } }
During development you can create a deploy.gradle, which will be used automatically.
// Insert code examples here
See Recipe: Provide Custom Deployment Configuration and Logic for additional places (like assemblies).
//... assemblyDeployment { //... purgeUnknownFiles = false }
Setting this value to true
will cause the undeployment process to delete all files inside known directories (such as local or share).
I want to deploy a local Eureka server and want to use it for service discovery.
It is necessary to configure the Eureka extension in the settings.gradle file for the host type 'serviceDiscovery'
before deploying the server. For details, see: Recipe: Configure the Deployment.
config { ... eureka { serverHostName = 'localhost' serverPort = 'my_port' serverUrlPath = 'eureka/' serverReplicaUrl = 'replica_url' serverEnvironment = 'LIVE' // service url is mandatory for clients instances (appserver, solr, microservices, etc.), but not within the settings.gradle for the host type serviceDiscovery it's not necessary // serviceUrls.default = 'http://<host_name>:<my_port>/eureka/' } }
Following attributes can be configured within a Eureka extension:
Attribute | Mandatory | Description |
---|---|---|
serverHostName | yes | The host name or IP where Eureka is deployed |
serverPort | yes | The port at which Eureka is operating on |
serverUrlPath | yes | The server URL suffix (in most cases eureka 'eureka/') Note Ensure to use the trailing slash '/' at the end. Otherwise the service discovery will not work properly. |
serverReplicaUrl | no | Eureka server replicas may be configured here. |
serverEnvironment | no | A property, which is shown in the Eureka UI |
serviceUrls | see info field | The URL, which Eureka clients use to register at Eureka server. The URL must be composed from the serverHostName, serverPort and serverUrlPath to use the locally deployed eureka (http://<serverHostName>:<serverPort>/<serverUrlPath>) serviceUrls It is mandatory for the settings.gradle of the instance, where the application server, the Solr server or the microservices will be deployed. See: Recipe: Register ICM at Eureka or Recipe: Microservice Deployment. Note Ensure to use the trailing slash '/' at the end. Otherwise the service discovery will not work properly. |
The serviceUrls
attribute provides the possibility to choose at which server the clients should be registered. This means, another Eureka server can be chosen to register clients.
For a software system using service discovery, both the clients and the servers need to be resilient.
Further information can be found here: Eureka Wiki
I want to register the ICM application server, the SolR server and the Web Adapter agent at the Eureka server.
You need to have access to an Eureka server: You can accomplish this by:
It is necessary to configure the extensions within the settings.gradle file for the according host types before deploying the server. For details, see: Recipe: Configure the Deployment.
config { appserver{ serviceAppName = 'appServerName' } solr{ serviceAppName = 'solrServerName' } eureka { serviceUrls.default = 'http://<host_name>:<my_port>/eureka/' } microservices { configProperties['intershop.naming.service.RecurringOrder'] = 'microserviceName' configProperties['intershop.naming.service.Scheduling'] = 'microserviceName' } }
config { solr{ serviceAppName = 'solrServerName' } eureka { serviceUrls.default = 'http://<host_name>:<my_port>/eureka/' } }
config { appserver{ serviceAppName = 'appServerName' } eureka { serviceUrls.default = 'http://<host_name>:<my_port>/eureka/' } }
serviceAppName
Attributes | Used within extension | Used in host type: share | Used in host type: solr | Used in host type: webserver | Description |
---|---|---|---|---|---|
serviceAppName | appserver | yes | yes | The name under which the application server is registered at the Eureka server | |
serviceAppName | solr | yes | yes | The name under which the SolR server is registered at the Eureka server | |
serviceUrls.default | eureka | yes | yes | yes | The Eureka URL, which is used to register at Eureka See: Recipe: Deploy a Local Eureka Server or the registration URL of a global Eureka server |
I want to deploy the microservices.
It is is necessary to have access to an Eureka server: You can accomplish this by the fulfillment of:
It is necessary to configure the extensions in the settings.gradle file for the host type 'microservices'
before deploying the server. For details, see Recipe: Configure the Deployment.
config { microservices { port = '<MY_PORT>' name = 'microserviceName' instanceId= 'microserviceInstanceId' configProperties['javax.persistence.jdbc.url'] = '<CONNECTION_URL_DATABASE>' configProperties['javax.persistence.jdbc.user'] = '<DATABASE_USER>' configProperties['javax.persistence.jdbc.password'] = '<DATABASE_PASSWORD>' configProperties['intershop.naming.service.RecurringOrder'] = 'microserviceName' configProperties['intershop.naming.service.Scheduling'] = 'microserviceName' } appserver{ serviceAppName = 'appServerName' } eureka { serviceUrls.default = 'http://<host_name>:<my_port>/eureka/' } }
Attribute | Extension | Description |
---|---|---|
port | microservices | The port on which the microservices are operating |
name | microservices | The name, which the microservices are using to register at Eureka server |
instanceId | microservices | The instance ID, Which the microservices are using to register at Eureka server |
configProperties | microservices | Map of configuration for the microservices |
configProperties['javax.persistence.jdbc.url'] | microservices | The database connection URL |
configProperties[javax.persistence.jdbc.user'] | microservices | The database user |
configProperties['javax.persistence.jdbc.password'] | microservices | The database password |
configProperties['intershop.naming.service.RecurringOrder'] | microservices | The name of the Recurring Order service |
configProperties['intershop.naming.service.Scheduling'] | microservices | The name of the Scheduling service |
serviceUrls.default | eureka | The Eureka URL, which is used to register at Eureka See: Recipe: Deploy a Local Eureka Server or the registration URL of a global Eureka server |
serviceAppName | appserver | The name the application server is registered at the Eureka server See Recipe: Register ICM at Eureka for details |
name
For naming restrictions of the name of the microservices, the scheduling and the recurring order service, please see the discussion
The configProperties
attribute allows to add further properties, which can be set during deployment without the need to adapt the microservice extension.
There is another JDBC property: javax.persistence.jdbc.driver
which is listed within the environment.properties of the microservices. This property was separated from the other JDBC properties, since it does not belong to the configuration.
The names of microservice, the Recurring Order service and the Scheduling service must be the same (name = 'microserviceName'
).
config { ... microservices { ... name = 'microserviceName' ... configProperties['intershop.naming.service.RecurringOrder'] = name configProperties['intershop.naming.service.Scheduling'] = name } }
Assume you have two instances <Instance_1> and <Instance_2>.
The service name (configProperties['intershop.naming.service.RecurringOrder'] = 'recurringOrder'
), that should be deployed on this instance, has to match to the name (
), which is used to register at Eureka server. The service name of the other service, which is deployed on the other instance, has to match to the name used by the other instance. So the settings.gradle files for the instances have to be configured the following wayname = 'recurringOrder'
config { microservices { name = 'recurringOrder' configProperties['intershop.naming.service.RecurringOrder'] = 'recurringOrder' configProperties['intershop.naming.service.Scheduling'] = 'scheduling' } }
config { microservices { name = 'scheduling' configProperties['intershop.naming.service.RecurringOrder'] = 'recurringOrder' configProperties['intershop.naming.service.Scheduling'] = 'scheduling' } }
The information provided in the Knowledge Base may not be applicable to all systems and situations. Intershop Communications will not be liable to any party for any direct or indirect damages resulting from the use of the Customer Support section of the Intershop Corporate Web site, including, without limitation, any lost profits, business interruption, loss of programs or other data on your information handling system.