Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bookworm",
"image": "mcr.microsoft.com/devcontainers/base:debian",
"customizations": {
"vscode": {
"settings": {
Expand All @@ -18,9 +18,16 @@
}
},
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/java:1": {
"version": "21",
"jdkDistro": "oracle",
"installMaven": true
}
},
"remoteUser": "node",
"updateContentCommand": "npm install -g @devcontainers/cli",
"postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}"
}
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.DS_Store
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ You will need to download the required packages from [Adobe's software distribut

![Software Distribution](software-distribution.png)

## [aem-lts](/src/aem-lts)
> Install and run AEM author and publish. You must have access to the AEM 6.5 LTS. It is only available through the Adobe software distribution site. This feature only facilitates the setup process.

## [aem-sdk](/src/aem-sdk)
> Install and run AEM author, publish and dispatcher. You must have access to the AEM SDK. It is only available through the Adobe software distribution site. This feature only facilitates the setup process. See: [Developing AEM Inside a Dev Container](https://theaemmaven.com/post/developing-aem-inside-a-dev-container)

Expand Down
40 changes: 40 additions & 0 deletions src/aem-lts/NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Adding the Feature to a Project

## Pre-requisites
* Visual Studio Code
* Docker
* The AEM LTS Quickstart Jar

## Step 1: The SDK Archive
* Navigate to Adobe's [Software Distribuition](https://experience.adobe.com/#/downloads) Site. Click on [Adobe Experience Manager](https://experience.adobe.com/#/downloads/content/software-distribution/en/aem.html). And click on [Download AEM 6.5 LTS](https://experience.adobe.com/#/downloads/content/software-distribution/en/aem.html?package=/content/software-distribution/en/details.html/content/dam/aem/public/adobe/packages/cq660/quickstart/cq-quickstart-6.6.0.jar)
* Place the JAR file in your project folder (i.e. `.devcontainer/cq-quickstart-6.6.0.jar`)

## Step 2: The Devcontainer Settings
* Add the following feature to the `.devcontainer/devcontainer.json` file
```jsonc
"features": {
"ghcr.io/juan-ayala/devcontainer-features/aem-lts:1": {
"quickstartJar": "${containerWorkspaceFolder}/.devcontainer/cq-quickstart-6.6.0.jar",
"licenseCustomerName": "Acme Corporation",
"licenseDownloadId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
```

## Step 3: Visual Studio Code
* Install the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers). And open the project folder.
* VSCode will detect `.devcontainer/devcontainer.json`. And prompt you to reopen the project in a devcontainer.

## Run AEM Services
In VSCode, open the terminal window. This is a terminal inside the docker container. You can run any command as needed, including Maven and Node.

There will be a script named `aem-lts`. Use this to start the author, publish or dispatcher.
* Start author: `aem-lts start author`
* Stop author: `aem-lts stop author`
* Start publish: `aem-lts start publish`
* Stop publish: `aem-lts stop publish`

The feature also sets up volume mounts for the author and publish services. This is where the services will persist the repository. So that if the container gets deleted and/or rebuilt, the repository will persist.

## References
* [Install local AEM Instances](https://experienceleague.adobe.com/en/docs/experience-manager-learn/foundation/development/set-up-a-local-aem-development-environment#install-local-aem-instances)
33 changes: 33 additions & 0 deletions src/aem-lts/bin/_globals.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash

source "${AEM_LTS_FEATURE_DIR}/options.sh"

function get_runmode_port()
{
local runmode="${1}"
if [ "${runmode}" = "publish" ]; then
echo "${AEM_LTS_PUBLISH_PORT}"
else
echo "${AEM_LTS_AUTHOR_PORT}"
fi
}

function aem_lts_err()
{
echo "${1}" >&2
exit 42
}

get_action() {
[ "${1}" = 'start' ] && action="${1}"
[ "${1}" = 'stop' ] && action="${1}"
[ -z "${action}" ] && action="start"
echo "${action}"
}

get_runmode() {
[ "${1}" = 'author' ] && service="${1}"
[ "${1}" = 'publish' ] && service="${1}"
[ -z "${service}" ] && service="author"
echo "${service}"
}
75 changes: 75 additions & 0 deletions src/aem-lts/bin/aem-lts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env bash

source "$(dirname $0)/_globals.sh"
action=$(get_action "${1}")
service=$(get_runmode "${2}")

echo "${action^}ing AEM ${service}..."

# copy the jar if not already there
JAR_NAME=$(basename "${AEM_LTS_QUICKSTART_JAR}")
jarFile="${AEM_LTS_FEATURE_DIR}/${JAR_NAME}"
if [[ ! -f "${jarFile}" ]]; then
if [[ -f "${AEM_LTS_QUICKSTART_JAR}" ]]; then
sudo cp "${AEM_LTS_QUICKSTART_JAR}" "${jarFile}"
else
aem_lts_err "Quickstart jar '${AEM_LTS_QUICKSTART_JAR}' not found"
fi
fi

# create the license file if not already there
licenceFile="${AEM_LTS_FEATURE_DIR}/license.properties"
if [[ ! -f "${licenceFile}" ]]; then

# check license properties
[[ -z "${AEM_LTS_LICENSE_CUSTOMER_NAME}" ]] && \
aem_lts_err "License customer name not set"
[[ -z "${AEM_LTS_LICENSE_DOWNLOAD_ID}" ]] && \
aem_lts_err "License download ID not set"

cat <<EOF | sudo tee "${licenceFile}" > /dev/null
license.customer.name=${AEM_LTS_LICENSE_CUSTOMER_NAME}
license.downloadID=${AEM_LTS_LICENSE_DOWNLOAD_ID}
license.product.name=Adobe Experience Manager
license.product.version=6.5.0.LTS
EOF

fi

runmodedir="${AEM_LTS_FEATURE_DIR}/${service}"

# link the jar if not already linked
jarFileLink="${runmodedir}/${JAR_NAME}"
[[ ! -L "${jarFileLink}" ]] && sudo ln -s "${jarFile}" "${jarFileLink}"

# link the license if not already linked
licenseFileLink="${runmodedir}/license.properties"
[[ ! -L "${licenseFileLink}" ]] && sudo ln -s "${licenceFile}" "${licenseFileLink}"

# make user owner of crx-quickstart (it is a volume mount)
sudo chown ${USER} "${runmodedir}/crx-quickstart"

case "${action}" in
start)

[[ -f "/tmp/aem-${service}.pid" ]] && aem_lts_err "AEM ${service} already running"

port=$(get_runmode_port ${service})
jvm_opts="-agentlib:jdwp=transport=dt_socket,address=*:3${port},server=y,suspend=n"
cq_opts="-nofork -nobrowser -nointeractive -r ${service} -p ${port}"

sudo start-stop-daemon --start --quiet --background --chuid root \
--make-pidfile --pidfile "/tmp/aem-${service}.pid" \
--name ${service} \
--chdir "$(dirname "${jarFileLink}")" \
--startas /bin/bash -- -c "exec ${JAVA_HOME}/bin/java ${jvm_opts} -jar "${jarFileLink}" ${cq_opts} \
> /var/log/aem-${service}.log 2>&1"
;;
stop)

sudo start-stop-daemon --stop --verbose \
--remove-pidfile --pidfile /tmp/aem-${service}.pid
;;
*)
aem_lts_err "Unknown action '${action}'"
esac
52 changes: 52 additions & 0 deletions src/aem-lts/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"id": "aem-lts",
"version": "1.0.0",
"name": "Adobe Experience Manager LTS",
"description": "Setup author and publish services. Requires the AEM LTS quickstart jar and license details.",
"options": {
"quickstartJar": {
"type": "string",
"description": "AEM LTS Quickstart Jar.",
"default": ""
},
"licenseCustomerName": {
"type": "string",
"description": "AEM LTS License Customer Name.",
"default": ""
},
"licenseDownloadId": {
"type": "string",
"description": "AEM LTS License Download Id.",
"default": ""
},
"authorPort": {
"type": "string",
"description": "Author service port",
"default": "4502"
},
"publishPort": {
"type": "string",
"description": "Publish service port",
"default": "4503"
}
},
"containerEnv": {
"AEM_LTS_FEATURE_DIR": "/aem-lts",
"PATH": "/aem-lts/bin:/aem-lts/dispatcher/bin:${PATH}"
},
"mounts": [
{
"source": "aem-lts-author-${devcontainerId}",
"target": "/aem-lts/author/crx-quickstart",
"type": "volume"
},
{
"source": "aem-lts-publish-${devcontainerId}",
"target": "/aem-lts/publish/crx-quickstart",
"type": "volume"
}
],
"installsAfter": [
"ghcr.io/devcontainers/features/java:1"
]
}
16 changes: 16 additions & 0 deletions src/aem-lts/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash

# create the feature directory
mkdir -p ${AEM_LTS_FEATURE_DIR}

# save feature properties
propertiesFile="${AEM_LTS_FEATURE_DIR}/options.sh"
echo "AEM_LTS_QUICKSTART_JAR=\"${QUICKSTARTJAR}\"" >> ${propertiesFile}
echo "AEM_LTS_LICENSE_CUSTOMER_NAME=\"${LICENSECUSTOMERNAME}\"" >> ${propertiesFile}
echo "AEM_LTS_LICENSE_DOWNLOAD_ID=\"${LICENSEDOWNLOADID}\"" >> ${propertiesFile}
echo "AEM_LTS_AUTHOR_PORT=\"${AUTHORPORT:-'4502'}\"" >> ${propertiesFile}
echo "AEM_LTS_PUBLISH_PORT=\"${PUBLISHPORT:-'4503'}\"" >> ${propertiesFile}
source ${propertiesFile}

# copy custom scripts
cp -r "$(dirname $0)/bin" ${AEM_LTS_FEATURE_DIR}
4 changes: 3 additions & 1 deletion src/aem-sdk/devcontainer-feature.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@
}
],
"dependsOn": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"moby": false
}
},
"installsAfter": [
"ghcr.io/devcontainers/features/java:1"
Expand Down
55 changes: 55 additions & 0 deletions test/aem-lts/defaults-with-quickstart.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/bash

set -e

source dev-container-features-test-lib

# Check options file created with defaults
source ${AEM_LTS_FEATURE_DIR}/options.sh
check "quickstartJar set" \
echo "${AEM_LTS_QUICKSTART_JAR}" | grep -E "^/workspaces/[0-9]+/.devcontainer/mock-cq-quickstart-6\.6\.0\.jar$"
check "licenseCustomerName set" \
[ "${AEM_LTS_LICENSE_CUSTOMER_NAME}" = "test-customer" ]
check "licenseDownloadId set" \
[ "${AEM_LTS_LICENSE_DOWNLOAD_ID}" = "test-download-id" ]
check "author port default" \
[ "${AEM_LTS_AUTHOR_PORT}" = "4502" ]
check "publish port default" \
[ "${AEM_LTS_PUBLISH_PORT}" = "4503" ]
# Check aem-lts in PATH is executable
check "aem-lts is +x" \
stat -c '%A' $(which aem-lts) | grep 'x.*x.*x'

# Check that author installs, starts & stops correctly
check "author: install & start" \
aem-lts start author
sleep 3 # give it time to start
check "author: check log for start message" \
grep 'Server started on port 4502' /var/log/aem-author.log
check "author: compare pid file to java process" \
[ $(cat /tmp/aem-author.pid) -eq $(pgrep -x java) ]
check "author: stop" \
aem-lts stop author
sleep 3 # give it time to stop
check "author: pid file should be removed" \
[ ! -f /tmp/aem-author.pid ]
check "author: no java process should be running" \
[ -z $(pgrep -x java) ]

# Check that publish installs, starts & stops correctly
check "publish: install & start" \
aem-lts start publish
sleep 3 # give it time to start
check "publish: check log for start message" \
grep 'Server started on port 4503' /var/log/aem-publish.log
check "publish: compare pid file to java process" \
[ $(cat /tmp/aem-publish.pid) -eq $(pgrep -x java) ]
check "publish: stop" \
aem-lts stop publish
sleep 3 # give it time to stop
check "publish: pid file should be removed" \
[ ! -f /tmp/aem-publish.pid ]
check "publish: no java process should be running" \
[ -z $(pgrep -x java) ]

reportResults
Binary file not shown.
55 changes: 55 additions & 0 deletions test/aem-lts/mock-http-server/SimpleHttpServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.regex.Pattern;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class SimpleHttpServer {

public static void main(String[] args) {

final var options = String.join(" ", args);
final var m = Pattern.compile("-p (\\d+)").matcher(options);
var matches = m.find();
if (matches) {

final var port = Integer.parseInt(m.group(1));

try {

final var server = HttpServer.create(new InetSocketAddress(port), 0);

server.createContext("/", new MyHandler());
server.setExecutor(null);
server.start();

} catch (IOException e) {
System.err.printf("Error starting the server: %s%n", e.getMessage());
System.exit(1);
}

System.out.printf("Server started on port %d%n", port);

} else {
System.err.println("Usage: java SimpleHttpServer -p <port>");
System.exit(2);
}
}

static class MyHandler implements HttpHandler {

@Override
public void handle(HttpExchange exchange) throws IOException {

final var response = "hello,world";
exchange.sendResponseHeaders(200, response.length());
final var os = exchange.getResponseBody();
os.write(response.getBytes());
os.close();
}

}
}
13 changes: 13 additions & 0 deletions test/aem-lts/mock-http-server/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash

[ -f "../defaults-with-quickstart/mock-cq-quickstart-6.6.0.jar" ] \
&& rm "../defaults-with-quickstart/mock-cq-quickstart-6.6.0.jar"

javac SimpleHttpServer.java
jar --create \
--file mock-cq-quickstart-6.6.0.jar \
--main-class=SimpleHttpServer *.class
rm *.class

cp mock-cq-quickstart-6.6.0.jar ../defaults-with-quickstart/
rm mock-cq-quickstart-6.6.0.jar
Loading