Friday, September 8, 2023

Support Custom Run Modes in AEM as a Cloud | Environment Specific Variables in AEM as a Cloud

 This post explores the approach to supporting current custom run modes in AEM as a Cloud using Cloud Manager environment-specific variables and OSGI configurations.

Run Modes lets you tune your AEM instance for a specific purpose: author or publish test, uat, development, intranet, or others.

You can:

  • Define collections of configuration parameters for each run mode.
  • A basic set of configuration parameters is applied for all run modes; you can then tune additional settings to the purpose of your specific environment. These are used as required.
  • Define additional bundles to be installed for a particular mode.

All settings and definitions are stored in the repository and activated by setting the Run Mode.

In AEM versions other than AEM as a Cloud (On-Prem, AMS, Hosted), apart from default run modes (Author, publish, samplecontent, nosamplecontent), we can define custom run modes such as test and uat. Let’s assume you have different AEM environments like Dev, UAT, Stage, and Prod, and each environment needs to connect to a corresponding third-party service, e.g., Dev Service, UAT Service, Stage Service, and Prod Service; this can be achieved by enabling a custom run mode to differentiate each environment then enable OSGI configurations based on the run mode(multiple run modes can be combined if required e.g. publish.uat)to enable environment specific service URL.

Create a configuration file in ui.config project— /apps/<Project Name>/osgiconfig/config.<RunModes>/<Persistent Identity>.cfg.json

The configurations that are common across all the environments can be placed under the config folder — /apps/<Project Name>/osgiconfig/config/<Persistent Identity>.cfg.json

e.g /apps/test/osgiconfig/config.uat/com.test.EndpointService.cfg.json

{
"serviceURL":"https://uat.service.com/testservice"
}

The run mode approach is changed in AEM as a Cloud Service; in AEM as a Cloud Service, run modes must reference RDE, development, stage, and production for the environment or author and publish for the service. A combination of <service>.<environment_type> is being supported, whereas these environments have to be used in this particular order (for example, author.dev or publish.prod)

In AEM as a Cloud service, the environment-specific configurations can be enabled using the Cloud manager environment variable and OSGI configuration. Two value types can be enabled — secret values and standard variables. The OSGI configurations can directly reference the Cloud Manager environment-specific values, replaced with actual values during the runtime.

{
"my_var1": "$[env:my_var1;default=val1]"
"my_var2": "$[secret:my_var1]"

}

As the stage and prod run modes are supported in AEM as a Cloud, the Major concern is on having multiple Dev environments(each AEM as a Cloud program by default enables one dev environment but allows the addition of additional Dev environments as required) and designating those for different purposes, e.g., UAT testing and QA testing, etc.; each Dev instance will have the run mode enabled as “Dev,” so by default, you will not be able to enable different configurations for different Dev environments by following the current approach. Still, you can do it for Stage and Prod.

You can follow two approaches.

  • Keep all the configurations under the config folder and separate any configurations that vary between authors and publisher into a config.author and config.publish run mode-specific folders and use Cloud Manager Environment variables in OSGI to enable environment-specific values.
  • Keep the configurations separated by Dev(config.dev), Stage(config.stage), and Prod(config.prod) run modes and also separated by Author and Publish run modes if required. Keep the Stage and Prod specific configurations directly on the Stage(config.stage) and Prod(config.prod) specific configurations. Then, use the Cloud Manager Environment variable to enable environment-specific configurations for Dev environments designated for different purposes.

Accessing the configuration without enabling the environment variable will display the placeholder string; the default value can be provided if required.

I am accessing the configuration value through a servlet.


@Component(service = { Servlet.class }, property = { "sling.servlet.paths=/services/endpoint",
"sling.servlet.methods"
+ "=GET" })

@Designate(ocd = EndpointService.EndpointServiceConfiguration.class)
public class EndpointService extends SlingSafeMethodsServlet {
private static final long serialVersionUID = 7699176851252742022L;

String endpoint;

@ObjectClassDefinition(name = "Endpoint Servlet")
public @interface EndpointServiceConfiguration {
@AttributeDefinition(name = "Endpoint", description = "Configure Endpoint")
String serviceURL() default "";
}

@Override
protected void doGet(SlingHttpServletRequest request,
SlingHttpServletResponse response)
throws ServletException, IOException {

response.getWriter().write("endpoint: " + endpoint);

}

@Activate
@Modified
protected void activate(EndpointServiceConfiguration config) {
this.endpoint = config.serviceURL();
}
}

You can use Cloud Manager Console or API to configure the Environment variables on Cloud Manager.

Login to Cloud Manager Console

Go to Environments and Select the View Details for the specific environment.

Click on Configuration

Add Configurations — Variable or Secret type, and also, the variable can be enabled for all the servers on the environment or specific to Author, Publish, or Preview.

Upon Save, the variable references are updated runtime; this may take some time.

Once the environment configuration update is completed, you can get the value.

You can check the OSGI configuration through the Developer Console, but this will only display the placeholder string not updated with the environment variable.

The variable can be deleted or updated if required; please note that it may take some time to reflect the changes, so plan your changes accordingly.

Also, you can enable secrets if required.

The Cloud Manager API or Command Line also can be used to manage the environment variables.

Dispatcher Configuration Per Environment:

The AMS or AEM as a Cloud uses the same configurations across all the environments and uses environment-specific server variables to support per-environment configurations.

By default, AEM as a Cloud is equipped with several environment variables. One such variable is ENVIRONMENT_TYPE, which indicates the current run mode, such as 'development', 'stage', or 'production'. This variable can be directly referenced in expressions. Additionally, there are "define" flags named ENVIRONMENT_DEVENVIRONMENT_STAGE, and ENVIRONMENT_PROD. These "define" flags can be utilized to construct logic using the <IfDefine> directive.

# Simple usage of the environment variable
ServerName ${ENVIRONMENT_TYPE}.company.com

# When more logic is required
<IfDefine ENVIRONMENT_STAGE>
# These statements are for stage
Define VIRTUALHOST stage.example.com
</IfDefine>
<IfDefine ENVIRONMENT_PROD>
# These statements are for production
Define VIRTUALHOST prod.example.com
</IfDefine>

In some cases, you may need custom variables, e.g., to separate each Dev environment for different use cases — Dev, UAT, etc.; in this case, you can use Cloud Manager environment variables, e.g., CUSTOM_VARIABLE in your httpd/dispatcher configuration, although not environment secrets. You can refer to this as a variable, e.g., ${CUSTOM_VARIABLE}, but the Define syntax defined in the earlier section will not work.

Refer to Configuring OSGi for Adobe Experience Manager as a Cloud Service | Adobe Experience Manager and Validating and Debugging using Dispatcher Tools | Adobe Experience Manager for more details on managing environment variables, including managing through API/Command lines, and also details on how local development can adopt this approach.