Skip to content

Commit

Permalink
Merge pull request #61 from shinesolutions/RS-161
Browse files Browse the repository at this point in the history
Add orchestrator logic for Preview Architecture
  • Loading branch information
mbloch1986 authored Jul 28, 2023
2 parents 2b40a9a + e98b334 commit 601820f
Show file tree
Hide file tree
Showing 26 changed files with 2,584 additions and 283 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ pom.xml.releaseBackup
release.properties
.idea/
aem-orchestrator.iml
core
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Add Preview-Publish & Preview-Publish-Dispatcher orchestration logic #RS-161

## [3.0.1] - 2020-12-02
### Fixed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.shinesolutions.aemorchestrator.actions;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.shinesolutions.aemorchestrator.aem.AgentRunMode;
import com.shinesolutions.aemorchestrator.aem.ReplicationAgentManager;
import com.shinesolutions.aemorchestrator.service.AemInstanceHelperService;
import com.shinesolutions.aemorchestrator.service.AwsHelperService;
import com.shinesolutions.swaggeraem4j.ApiException;

@Component
public class ScaleDownPreviewPublishAction implements Action {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Value("${aem.reverseReplication.enable}")
private boolean reverseReplicationEnabled;

@Resource
private AemInstanceHelperService aemHelperService;

@Resource
private AwsHelperService awsHelperService;

@Resource
private ReplicationAgentManager replicationAgentManager;

public boolean execute(String instanceId) {
logger.info("ScaleDownPreviewPublishAction executing");

// Delete paired dispatcher
String pairedDispatcherId = aemHelperService.getDispatcherIdForPairedPreviewPublish(instanceId);
logger.debug("Paired previewPublish dispatcher instance ID=" + pairedDispatcherId);

if(pairedDispatcherId != null) {
logger.info("Terminating paired previewPublish dispatcher with ID: " + pairedDispatcherId);
awsHelperService.terminateInstance(pairedDispatcherId);
} else {
logger.warn("Unable to terminate paired previewPublish dispatcher with ID: " + pairedDispatcherId +
". It may already be terminated");
}

// Delete replication agent on author
String authorAemBaseUrl = aemHelperService.getAemUrlForAuthorElb();

try {
replicationAgentManager.deletePreviewReplicationAgent(instanceId, authorAemBaseUrl, AgentRunMode.AUTHOR);
} catch (ApiException e) {
logger.warn("Failed to delete replication agent on author for previewPublish id: " + instanceId +
". It may already be deleted.");
}

// Remove and reverse replication agents if they exist
if (reverseReplicationEnabled) {
logger.debug("Reverse replication is enabled");
try {
replicationAgentManager.deletePreviewReverseReplicationAgent(instanceId, authorAemBaseUrl,
AgentRunMode.AUTHOR);

} catch (ApiException e) {
logger.warn("Failed to delete reverse replication agent on author for previewPublish id " + instanceId
+ ". It may already be deleted.");
}
}

// Delete the attached content health check alarm
try {
aemHelperService.deleteContentHealthAlarmForPreviewPublisher(instanceId);
} catch (Exception e) {
logger.warn("Failed to remove content health check alarm for previewPublish instance " + instanceId, e);
}

return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.shinesolutions.aemorchestrator.actions;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.shinesolutions.aemorchestrator.service.AemInstanceHelperService;
import com.shinesolutions.aemorchestrator.service.AwsHelperService;

@Component
public class ScaleDownPreviewPublishDispatcherAction implements Action {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Resource
private AemInstanceHelperService aemHelperService;

@Resource
private AwsHelperService awsHelperService;

public boolean execute(String instanceId) {
logger.info("ScaleDownPreviewPublishDispatcherAction executing");

// Find and terminate paired previewPublish instance
String pairedPreviewPublishId = aemHelperService.getPreviewPublishIdForPairedDispatcher(instanceId);
logger.debug("Paired previewPublish instance ID=" + pairedPreviewPublishId);

if (pairedPreviewPublishId != null) {
// Terminate paired previewPublish instance
logger.info("Terminating paired previewPublish instance with ID: " + pairedPreviewPublishId);
awsHelperService.terminateInstance(pairedPreviewPublishId);
} else {
logger.warn("Unable to terminate paired previewPublish instance with ID: " + pairedPreviewPublishId +
". It may already be terminated");
}

// Change previewPublish auto scaling group desired capacity to match dispatcher
int currentDispatcherDesiredCapacity = aemHelperService
.getAutoScalingGroupDesiredCapacityForPreviewPublishDispatcher();
int currentPreviewPublishDesiredCapacity = aemHelperService.getAutoScalingGroupDesiredCapacityForPreviewPublish();

if (currentDispatcherDesiredCapacity == currentPreviewPublishDesiredCapacity) {
// If desired capacity already the same, then don't do anything
logger.info("Desired capacity already matching for previewPublish and dispatcher. No changes will be made");
} else {
logger.info("Changing previewPublish auto scaling group capacity of " + currentPreviewPublishDesiredCapacity +
" to match dispatcher's capacity of " + currentDispatcherDesiredCapacity);
aemHelperService.setAutoScalingGroupDesiredCapacityForPreviewPublish(currentDispatcherDesiredCapacity);
}

return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package com.shinesolutions.aemorchestrator.actions;

import java.util.NoSuchElementException;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.shinesolutions.aemorchestrator.aem.AgentRunMode;
import com.shinesolutions.aemorchestrator.aem.ReplicationAgentManager;
import com.shinesolutions.aemorchestrator.exception.InstanceNotInHealthyStateException;
import com.shinesolutions.aemorchestrator.service.AemInstanceHelperService;
import com.shinesolutions.aemorchestrator.service.AwsHelperService;
import com.shinesolutions.swaggeraem4j.ApiException;

@Component
public class ScaleUpPreviewPublishAction implements Action {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Value("${aem.reverseReplication.enable}")
private boolean enableReverseReplication;

@Value("${aws.device.name}")
private String awsDeviceName;

@Resource
private AemInstanceHelperService aemHelperService;

@Resource
private AwsHelperService awsHelperService;

@Resource
private ReplicationAgentManager replicationAgentManager;


public boolean execute(String instanceId) {
logger.info("ScaleUpPreviewPublishAction executing");

// First create replication agent on previewPublish instance
String authorAemBaseUrl = aemHelperService.getAemUrlForAuthorElb();
String previewPublishAemBaseUrl = aemHelperService.getAemUrlForPreviewPublish(instanceId);

// Find unpaired previewPublish dispatcher and pair it with tags
boolean success = pairAndTagWithDispatcher(instanceId, authorAemBaseUrl);

if (success) {
success = prepareReplicationAgent(instanceId, authorAemBaseUrl, previewPublishAemBaseUrl);
}

// Create a new previewPublish from a snapshot of an active previewPublish instance
if (success) {
success = loadSnapshotFromActivePreviewPublisher(instanceId, authorAemBaseUrl);
}

if (success) {
attachContentHealthCheckAlarm(instanceId);
}

return success;
}


private boolean prepareReplicationAgent(String instanceId, String authorAemBaseUrl, String previewPublishAemBaseUrl) {
boolean success = true;
try {
replicationAgentManager.createPreviewReplicationAgent(instanceId, previewPublishAemBaseUrl, authorAemBaseUrl,
AgentRunMode.PREVIEWPUBLISH);

if(enableReverseReplication) {
logger.debug("Reverse replication is enabled");
replicationAgentManager.createPreviewReverseReplicationAgent(instanceId, previewPublishAemBaseUrl,
authorAemBaseUrl, AgentRunMode.PREVIEWPUBLISH);
}

} catch (ApiException e) {
logger.error("Error while attempting to create a new previewPublish replication agent for previewPublish instance "
+ instanceId, e);
success = false;
}
return success;
}


private boolean loadSnapshotFromActivePreviewPublisher(String instanceId, String authorAemBaseUrl) {
boolean success = true;

if(aemHelperService.isFirstPreviewPublishInstance()) {
logger.info("First previewPublish instance, no snapshot needed");
aemHelperService.tagInstanceWithSnapshotId(instanceId, ""); //Tag with empty Snapshot ID
} else {
String activePreviewPublishId = aemHelperService.getPreviewPublishIdToSnapshotFrom(instanceId);
logger.debug("Active previewPublish instance id to snapshot from: " + activePreviewPublishId);

logger.info("Waiting for active previewPublish instance " + activePreviewPublishId + " to be in an healthy state");
try {
aemHelperService.waitForPreviewPublishToBeHealthy(activePreviewPublishId);
logger.info("Active previewPublish instance " + activePreviewPublishId + " is in a healthy state");
} catch (InstanceNotInHealthyStateException e) {
logger.warn("Active previewPublish instance " + activePreviewPublishId + " is NOT in a healthy state. "
+ "Unable to take snapshot");
success = false;
}

if(success) {
success = performSnapshot(instanceId, activePreviewPublishId, authorAemBaseUrl);
}
}

return success;
}

private boolean performSnapshot(String instanceId, String activePreviewPublishId, String authorAemBaseUrl) {
boolean success = true;

// Pause active previewPublish's replication agent before taking snapshot
try {
replicationAgentManager.pausePreviewReplicationAgent(activePreviewPublishId, authorAemBaseUrl, AgentRunMode.PREVIEWPUBLISH);
// Take snapshot
String volumeId = awsHelperService.getVolumeId(activePreviewPublishId, awsDeviceName);

logger.debug("Volume ID for snapshot: " + volumeId);

if (volumeId != null) {
String snapshotId = aemHelperService.createPreviewPublishSnapshot(activePreviewPublishId, volumeId);
logger.info("Created snapshot with ID: " + snapshotId);

aemHelperService.tagInstanceWithSnapshotId(instanceId, snapshotId);
} else {
logger.error("Unable to find volume id for block device '" + awsDeviceName + "' and instance id "
+ activePreviewPublishId);
success = false;
}

} catch (Exception e) {
logger.error("Error while pausing and attempting to snapshot an active preview Publish instance", e);
success = false;
} finally {
// Always need to resume active previewPublish instance replication queue
try {
replicationAgentManager.resumePreviewReplicationAgent(activePreviewPublishId, authorAemBaseUrl,
AgentRunMode.PREVIEWPUBLISH);
} catch (ApiException e) {
logger.error("Failed to restart replication queue for active previewPublish instance: " + activePreviewPublishId, e);
}
}

return success;
}


private boolean pairAndTagWithDispatcher(String instanceId, String authorAemBaseUrl) {
boolean success = true;

try {
// Find unpaired previewPublish dispatcher and pair it with tags
logger.debug("Attempting to find unpaired Preview Publish dispatcher instance");
String unpairedDispatcherId = aemHelperService.findUnpairedPreviewPublishDispatcher(instanceId);

logger.debug("Pairing previewPublish instance (" + instanceId + ") with preview publish dispatcher ("
+ unpairedDispatcherId + ") via tags");
aemHelperService.pairPreviewPublishWithDispatcher(instanceId, unpairedDispatcherId);

} catch (NoSuchElementException nse) {
logger.warn("Failed to find unpaired previewPublish dispatcher", nse);
success = false;
} catch (Exception e) {
logger.error("Error while attempting to pair previewPublish instance (" +
instanceId + ") with dispatcher", e);
success = false;
}

return success;
}


private void attachContentHealthCheckAlarm(String instanceId) {
try {
logger.info("Creating content health check alarm");
aemHelperService.createContentHealthAlarmForPreviewPublisher(instanceId);
} catch (Exception e) {
logger.warn("Failed to create content health check alarm for Preview Publish instance " + instanceId, e);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.shinesolutions.aemorchestrator.actions;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.shinesolutions.aemorchestrator.service.AemInstanceHelperService;

@Component
public class ScaleUpPreviewPublishDispatcherAction implements Action {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Resource
private AemInstanceHelperService aemHelperService;

public boolean execute(String instanceId) {
logger.info("ScaleUpPreviewPublishDispatcherAction executing");

// Change previewPublish auto scaling group desired capacity to match dispatcher
int currentDispatcherDesiredCapacity = aemHelperService
.getAutoScalingGroupDesiredCapacityForPreviewPublishDispatcher();
int currentPreviewPublishDesiredCapacity = aemHelperService.getAutoScalingGroupDesiredCapacityForPreviewPublish();

if (currentDispatcherDesiredCapacity == currentPreviewPublishDesiredCapacity) {
// If desired capacity already the same, then don't do anything
logger.info("Desired capacity already matching for previewPublish auto scaling group and it's dispatcher. No changes will be made");
} else {
logger.info("Changing previewPublish auto scaling group capacity of " + currentPreviewPublishDesiredCapacity +
" to match dispatcher's capacity of " + currentDispatcherDesiredCapacity);
aemHelperService.setAutoScalingGroupDesiredCapacityForPreviewPublish(currentDispatcherDesiredCapacity);
}

return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ private boolean pairAndTagWithDispatcher(String instanceId, String authorAemBase
logger.debug("Attempting to find unpaired publish dispatcher instance");
String unpairedDispatcherId = aemHelperService.findUnpairedPublishDispatcher(instanceId);

logger.debug("Pairing publish instance (" + instanceId + ") with pubish dispatcher ("
logger.debug("Pairing publish instance (" + instanceId + ") with preview publish dispatcher ("
+ unpairedDispatcherId + ") via tags");
aemHelperService.pairPublishWithDispatcher(instanceId, unpairedDispatcherId);

Expand Down
Loading

0 comments on commit 601820f

Please sign in to comment.