in services/settings-service/src/main/java/com/amazon/aws/partners/saasfactory/saasboost/SettingsService.java [602:724]
public APIGatewayProxyResponseEvent updateAppConfig(Map<String, Object> event, Context context) {
if (Utils.isBlank(SAAS_BOOST_EVENT_BUS)) {
throw new IllegalStateException("Missing environment variable SAAS_BOOST_EVENT_BUS");
}
if (Utils.isBlank(API_GATEWAY_HOST)) {
throw new IllegalStateException("Missing required environment variable API_GATEWAY_HOST");
}
if (Utils.isBlank(API_GATEWAY_STAGE)) {
throw new IllegalStateException("Missing required environment variable API_GATEWAY_STAGE");
}
if (Utils.isBlank(API_TRUST_ROLE)) {
throw new IllegalStateException("Missing required environment variable API_TRUST_ROLE");
}
if (Utils.warmup(event)) {
//LOGGER.info("Warming up");
return new APIGatewayProxyResponseEvent().withHeaders(CORS).withStatusCode(200);
}
final long startTimeMillis = System.currentTimeMillis();
LOGGER.info("SettingsService::updateAppConfig");
Utils.logRequestEvent(event);
APIGatewayProxyResponseEvent response = null;
try {
AppConfig updatedAppConfig = Utils.fromJson((String) event.get("body"), AppConfig.class);
if (updatedAppConfig == null) {
response = new APIGatewayProxyResponseEvent()
.withHeaders(CORS)
.withStatusCode(400)
.withBody("{\"message\":\"Empty request body.\"}");
} else if (updatedAppConfig.getName() == null || updatedAppConfig.getName().isEmpty()) {
LOGGER.error("Can't update application configuration without an app name");
response = new APIGatewayProxyResponseEvent()
.withHeaders(CORS)
.withStatusCode(400)
.withBody("{\"message\":\"Application name is required.\"");
} else {
AppConfig currentAppConfig = dal.getAppConfig();
updatedAppConfig = dal.setAppConfig(updatedAppConfig);
if (AppConfigHelper.isDomainChanged(currentAppConfig, updatedAppConfig)) {
LOGGER.info("AppConfig domain name has changed");
triggerDomainNameChange();
}
if (AppConfigHelper.isBillingChanged(currentAppConfig, updatedAppConfig)) {
String apiKey1 = currentAppConfig.getBilling() != null ? currentAppConfig.getBilling().getApiKey() : null;
String apiKey2 = updatedAppConfig.getBilling() != null ? updatedAppConfig.getBilling().getApiKey() : null;
LOGGER.info("AppConfig billing provider has changed {} != {}", apiKey1, apiKey2);
if (AppConfigHelper.isBillingFirstTime(currentAppConfig, updatedAppConfig)) {
// 1. We didn't have a billing provider and now we do, trigger setup
// Existing provisioned tenants won't be subscribed to a billing plan
// so we don't need to update the tenant stacks.
LOGGER.info("AppConfig now has a billing provider. Triggering billing setup.");
triggerBillingSetup();
} else if (AppConfigHelper.isBillingRemoved(currentAppConfig, updatedAppConfig)) {
// 2. We had a billing provider and now we don't, disable integration
LOGGER.info("AppConfig has removed the billing provider.");
// TODO how do we cleanup the billing provider integration?
} else {
// 3. We had a billing provider and we're just changing the value of the key, that is
// taken care of by dal.setAppConfig and we don't need to trigger a setup because
// it's already been done.
LOGGER.info("AppConfig billing provider API key in-place change.");
}
}
if (AppConfigHelper.isComputeChanged(currentAppConfig, updatedAppConfig) ||
AppConfigHelper.isAutoScalingChanged(currentAppConfig, updatedAppConfig)) {
LOGGER.info("AppConfig compute and/or scaling has changed. Triggering update of default setting tenants.");
// Get all the provisioned tenants who have not customized
// their compute settings so we can update them to the new
// global settings.
ApiRequest getTenantsRequest = ApiRequest.builder()
.resource("tenants/provisioned?overrideDefaults=false")
.method("GET")
.build();
SdkHttpFullRequest getTenantsApiRequest = ApiGatewayHelper.getApiRequest(API_GATEWAY_HOST, API_GATEWAY_STAGE, getTenantsRequest);
try {
String getTenantsResponseBody = ApiGatewayHelper.signAndExecuteApiRequest(getTenantsApiRequest, API_TRUST_ROLE, context.getAwsRequestId());
ArrayList<Map<String, Object>> provisionedTenantsWithDefaultSettings = Utils.fromJson(getTenantsResponseBody, ArrayList.class);
if (provisionedTenantsWithDefaultSettings != null) {
LOGGER.info("{} tenants with default settings to update", provisionedTenantsWithDefaultSettings.size());
for (Map<String, Object> tenant : provisionedTenantsWithDefaultSettings) {
// The onboarding service update tenant call expects to be given the
// values to use as parameters for the CloudFormation stack.
// AppConfig will delegate to ComputeSize for memory and cpu if it's set.
tenant.put("memory", updatedAppConfig.getDefaultMemory());
tenant.put("cpu", updatedAppConfig.getDefaultCpu());
tenant.put("minCount", updatedAppConfig.getMinCount());
tenant.put("maxCount", updatedAppConfig.getMaxCount());
LOGGER.info("Triggering update for tenant {}", tenant.get("id"));
Map<String, Object> systemApiRequest = new HashMap<>();
systemApiRequest.put("resource", "onboarding/update/tenant");
systemApiRequest.put("method", "PUT");
systemApiRequest.put("body", Utils.toJson(tenant));
publishEvent(SYSTEM_API_CALL_DETAIL_TYPE, SYSTEM_API_CALL_SOURCE, systemApiRequest);
}
}
} catch (Exception e) {
LOGGER.error("Error invoking API " + API_GATEWAY_STAGE + "/tenants/provisioned?overrideDefaults=false");
LOGGER.error(Utils.getFullStackTrace(e));
throw new RuntimeException(e);
}
}
response = new APIGatewayProxyResponseEvent()
.withStatusCode(200)
.withHeaders(CORS)
.withBody(Utils.toJson(updatedAppConfig));
}
} catch (Exception e) {
LOGGER.error("Unable to update");
response = new APIGatewayProxyResponseEvent()
.withHeaders(CORS)
.withStatusCode(400)
.withBody("{\"message\":\"Invalid JSON\"}");
}
long totalTimeMillis = System.currentTimeMillis() - startTimeMillis;
LOGGER.info("SettingsService::updateAppConfig exec " + totalTimeMillis);
return response;
}