Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Commit

Permalink
Merge pull request #40 from Nike-Inc/feature/add_update_cms_config_co…
Browse files Browse the repository at this point in the history
…mmand

Add update-cms-config command
  • Loading branch information
sdford authored May 5, 2017
2 parents c9f947d + 3fe5cdc commit ba7ee03
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 64 deletions.
30 changes: 30 additions & 0 deletions src/main/java/com/nike/cerberus/ConfigConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.nike.cerberus;

import com.google.common.collect.ImmutableSet;

public class ConfigConstants {

public static final String ENV_PREFIX = "cerberus-";
Expand Down Expand Up @@ -77,4 +79,32 @@ public class ConfigConstants {
public static final String CF_ELB_IP_SYNC_STACK_TEMPLATE_PATH = "/cloudformation/cloudfront-elb-security-group-updater-lambda.json";

public static final String VERSION_PROPERTY = "cli.version";

public static final String CMS_ADMIN_GROUP_KEY = "cms.admin.group";

public static final String VAULT_ADDR_KEY = "vault.addr";

public static final String VAULT_TOKEN_KEY = "vault.token";

public static final String ROOT_USER_ARN_KEY = "root.user.arn";

public static final String ADMIN_ROLE_ARN_KEY = "admin.role.arn";

public static final String CMS_ROLE_ARN_KEY = "cms.role.arn";

public static final String JDBC_URL_KEY = "JDBC.url";

public static final String JDBC_USERNAME_KEY = "JDBC.username";

public static final String JDBC_PASSWORD_KEY ="JDBC.password";

public static final ImmutableSet<String> SYSTEM_CONFIGURED_CMS_PROPERTIES = ImmutableSet.of(
VAULT_ADDR_KEY,
VAULT_TOKEN_KEY,
ROOT_USER_ARN_KEY,
ADMIN_ROLE_ARN_KEY,
CMS_ROLE_ARN_KEY,
JDBC_URL_KEY,
JDBC_USERNAME_KEY,
JDBC_PASSWORD_KEY);
}
2 changes: 2 additions & 0 deletions src/main/java/com/nike/cerberus/cli/CerberusRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.nike.cerberus.command.Command;
import com.nike.cerberus.command.cms.CreateCmsClusterCommand;
import com.nike.cerberus.command.cms.CreateCmsConfigCommand;
import com.nike.cerberus.command.cms.UpdateCmsConfigCommand;
import com.nike.cerberus.command.core.ViewConfigCommand;
import com.nike.cerberus.command.consul.CreateConsulClusterCommand;
import com.nike.cerberus.command.consul.CreateConsulConfigCommand;
Expand Down Expand Up @@ -196,6 +197,7 @@ private void registerAllCommands() {
registerCommand(new WhitelistCidrForVpcAccessCommand());
registerCommand(new RestoreCompleteCerberusDataFromS3BackupCommand());
registerCommand(new ViewConfigCommand());
registerCommand(new UpdateCmsConfigCommand());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.nike.cerberus.command.StackDelegate;
import com.nike.cerberus.command.cms.CreateCmsClusterCommand;
import com.nike.cerberus.command.cms.CreateCmsConfigCommand;
import com.nike.cerberus.command.cms.UpdateCmsConfigCommand;
import com.nike.cerberus.command.consul.CreateConsulClusterCommand;
import com.nike.cerberus.command.core.CreateBaseCommand;
import com.nike.cerberus.command.core.UpdateStackCommand;
Expand Down Expand Up @@ -111,6 +112,8 @@ private static List<String> getArgsForCommand(EnvironmentConfig environmentConfi
return getPublishLambdaCommandArgs(environmentConfig, passedArgs);
case CreateCloudFrontLogProcessingLambdaConfigCommand.COMMAND_NAME:
return getCreateCloudFrontLogProcessingLambdaConfigCommandArgs(environmentConfig);
case UpdateCmsConfigCommand.COMMAND_NAME:
return getCreateCmsConfigCommandArgs(environmentConfig);
default:
return new LinkedList<>();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2017 Nike, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.nike.cerberus.command.cms;

import com.beust.jcommander.DynamicParameter;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.nike.cerberus.command.Command;
import com.nike.cerberus.operation.Operation;
import com.nike.cerberus.operation.cms.UpdateCmsConfigOperation;

import java.util.HashMap;
import java.util.Map;

import static com.nike.cerberus.command.cms.CreateCmsClusterCommand.COMMAND_NAME;

/**
* Command to create the CMS cluster.
*/
@Parameters(commandNames = COMMAND_NAME, commandDescription = "Updates the CMS config.")
public class UpdateCmsConfigCommand implements Command {

public static final String COMMAND_NAME = "update-cms-config";
public static final String OVERWRITE_LONG_ARG = "--overwrite";

@Parameter(names = CreateCmsConfigCommand.ADMIN_GROUP_LONG_ARG, description = "Group that has admin privileges in CMS.")
private String adminGroup;

@Parameter(names = OVERWRITE_LONG_ARG, description = "Overwrite -P parameters completely.")
private boolean overwrite;

@DynamicParameter(names = CreateCmsConfigCommand.PROPERTY_SHORT_ARG, description = "Dynamic parameters for setting additional properties in the CMS environment configuration.")
private Map<String, String> additionalProperties = new HashMap<>();

public String getAdminGroup() {
return adminGroup;
}

public boolean getOverwrite() {
return overwrite;
}

public Map<String, String> getAdditionalProperties() {
return additionalProperties;
}

@Override
public String getCommandName() {
return COMMAND_NAME;
}

@Override
public Class<? extends Operation<?>> getOperationClass() {
return UpdateCmsConfigOperation.class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,16 @@

package com.nike.cerberus.operation.cms;

import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.model.GetCallerIdentityRequest;
import com.amazonaws.services.securitytoken.model.GetCallerIdentityResult;
import com.google.common.collect.Maps;
import com.nike.cerberus.ConfigConstants;
import com.nike.cerberus.command.cms.CreateCmsConfigCommand;
import com.nike.cerberus.domain.cloudformation.BaseOutputs;
import com.nike.cerberus.domain.cloudformation.BaseParameters;
import com.nike.cerberus.domain.cloudformation.VaultParameters;
import com.nike.cerberus.operation.Operation;
import com.nike.cerberus.store.ConfigStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;

import static com.nike.cerberus.ConfigConstants.CMS_ADMIN_GROUP_KEY;

/**
* Gathers all of the CMS environment configuration and puts it in the config bucket.
Expand All @@ -43,81 +36,42 @@ public class CreateCmsConfigOperation implements Operation<CreateCmsConfigComman

private final ConfigStore configStore;

private final AWSSecurityTokenService securityTokenService;

@Inject
public CreateCmsConfigOperation(final ConfigStore configStore,
final AWSSecurityTokenService securityTokenService) {
public CreateCmsConfigOperation(final ConfigStore configStore) {
this.configStore = configStore;
this.securityTokenService = securityTokenService;
}

@Override
public void run(final CreateCmsConfigCommand command) {
configStore.storeCmsAdminGroup(command.getAdminGroup());

logger.info("Retrieving configuration data from the configuration bucket.");
final BaseOutputs baseOutputs = configStore.getBaseStackOutputs();
final BaseParameters baseParameters = configStore.getBaseStackParameters();
final VaultParameters vaultParameters = configStore.getVaultStackParamters();
final GetCallerIdentityResult callerIdentity = securityTokenService.getCallerIdentity(
new GetCallerIdentityRequest());
final Optional<String> cmsVaultToken = configStore.getCmsVaultToken();
final Optional<String> cmsDatabasePassword = configStore.getCmsDatabasePassword();

final Map<String, String> cmsConfigMap = Maps.newHashMap();
final String rootUserArn = String.format("arn:aws:iam::%s:root", callerIdentity.getAccount());

cmsConfigMap.put("vault.addr", String.format("https://%s", cnameToHost(vaultParameters.getCname())));
cmsConfigMap.put("vault.token", cmsVaultToken.get());
cmsConfigMap.put("cms.admin.group", command.getAdminGroup());
cmsConfigMap.put("root.user.arn", rootUserArn);
cmsConfigMap.put("admin.role.arn", baseParameters.getAccountAdminArn());
cmsConfigMap.put("cms.role.arn", baseOutputs.getCmsIamRoleArn());
cmsConfigMap.put("JDBC.url", baseOutputs.getCmsDbJdbcConnectionString());
cmsConfigMap.put("JDBC.username", ConfigConstants.DEFAULT_CMS_DB_NAME);
cmsConfigMap.put("JDBC.password", cmsDatabasePassword.get());
final Properties cmsConfigProperties = configStore.getCmsSystemProperties();

cmsConfigProperties.put(CMS_ADMIN_GROUP_KEY, command.getAdminGroup());

command.getAdditionalProperties().forEach((k, v) -> {
if (!cmsConfigMap.containsKey(k)) {
cmsConfigMap.put(k, v);
if (!cmsConfigProperties.containsKey(k)) {
cmsConfigProperties.put(k, v);
} else {
logger.warn("Ignoring additional property that would override system configured property, " + k);
}
});

logger.info("Uploading the CMS configuration to the configuration bucket.");
configStore.storeCmsEnvConfig(cmsConfigMap);
configStore.storeCmsEnvConfig(cmsConfigProperties);

logger.info("Uploading complete.");
}

@Override
public boolean isRunnable(final CreateCmsConfigCommand command) {
boolean isRunnable = true;
final Optional<String> cmsVaultToken = configStore.getCmsVaultToken();
final Optional<String> cmsDatabasePassword = configStore.getCmsDatabasePassword();
boolean isRunnable = !configStore.getCmsEnvConfig().isPresent();

if (!cmsVaultToken.isPresent()) {
logger.error("CMS Vault token not present for specified environment.");
isRunnable = false;
}

if (!cmsDatabasePassword.isPresent()) {
logger.error("CMS database password not present for specified environment.");
isRunnable = false;
if (! isRunnable) {
logger.warn("CMS config already exists, use 'update-cms-config' command.");
}

return isRunnable;
}

/**
* Removes the final '.' from the CNAME.
*
* @param cname The cname to convert
* @return The host derived from the CNAME
*/
private String cnameToHost(final String cname) {
return cname.substring(0, cname.length() - 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright (c) 2017 Nike, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.nike.cerberus.operation.cms;

import com.nike.cerberus.command.cms.UpdateCmsConfigCommand;
import com.nike.cerberus.operation.Operation;
import com.nike.cerberus.store.ConfigStore;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.util.Optional;
import java.util.Properties;

import static com.nike.cerberus.ConfigConstants.SYSTEM_CONFIGURED_CMS_PROPERTIES;
import static com.nike.cerberus.ConfigConstants.CMS_ADMIN_GROUP_KEY;

/**
* Gathers all of the CMS environment configuration and puts it in the config bucket.
*/
public class UpdateCmsConfigOperation implements Operation<UpdateCmsConfigCommand> {

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

private final ConfigStore configStore;

@Inject
public UpdateCmsConfigOperation(final ConfigStore configStore) {
this.configStore = configStore;
}

@Override
public void run(final UpdateCmsConfigCommand command) {

logger.debug("Retrieving configuration data from the configuration bucket.");

final Properties newProperties = configStore.getCmsSystemProperties();
final Properties existingCustomProperties = configStore.getExistingCmsUserProperties();
if (! command.getOverwrite()) {
// keep existing custom properties
newProperties.putAll(existingCustomProperties);
}

// update existing custom properties, add new ones
command.getAdditionalProperties().forEach((k, v) -> {
if (! SYSTEM_CONFIGURED_CMS_PROPERTIES.contains(k)) {
newProperties.put(k, v);
} else {
logger.warn("Ignoring additional property that would override system configured property, " + k);
}
});

final String existingAdminGroup = existingCustomProperties.getProperty(CMS_ADMIN_GROUP_KEY);
final String adminGroupParameter = command.getAdminGroup();
String newAdminGroupValue = existingAdminGroup; // keep existing admin group by default

if (shouldOverwriteAdminGroup(existingAdminGroup, adminGroupParameter)) {
logger.warn(String.format("Updating CMS admin group from '%s' to '%s'", existingAdminGroup, adminGroupParameter));
configStore.storeCmsAdminGroup(adminGroupParameter);
newAdminGroupValue = adminGroupParameter; // overwrite admin group
}
newProperties.put(CMS_ADMIN_GROUP_KEY, newAdminGroupValue);

logger.info("Uploading the CMS configuration to the configuration bucket.");
configStore.storeCmsEnvConfig(newProperties);

logger.info("Uploading complete.");
}

@Override
public boolean isRunnable(final UpdateCmsConfigCommand command) {
boolean isRunnable = true;
final Optional<String> cmsVaultToken = configStore.getCmsVaultToken();
final Optional<String> cmsDatabasePassword = configStore.getCmsDatabasePassword();

if (!cmsVaultToken.isPresent()) {
logger.error("CMS Vault token not present for specified environment.");
isRunnable = false;
}

if (!cmsDatabasePassword.isPresent()) {
logger.error("CMS database password not present for specified environment.");
isRunnable = false;
}

return isRunnable;
}

private boolean shouldOverwriteAdminGroup(final String existingAdminGroup, final String newAdminGroup) {
if (newAdminGroup == null && existingAdminGroup == null) {
throw new IllegalStateException("Admin group does not exist in S3 config and was not provided as a " +
"parameter. Please use --admin-group parameter to fix.");
}

if (newAdminGroup == null) {
logger.warn("Admin group not provided, using existing group.");
return false;
}

return !StringUtils.equals(newAdminGroup, existingAdminGroup);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void run(final ViewConfigCommand command) {
if (fileContents.isPresent()) {
logger.info(fileContents.get());
} else {
logger.error("Failed to load config file: %s", command.getPathToConfig());
logger.error(String.format("Failed to load config file: '%s'", command.getPathToConfig()));
}
}

Expand Down
Loading

0 comments on commit ba7ee03

Please sign in to comment.