in java-operator/src/main/java/com/amazonwebservices/blogs/containers/kubernetes/IamUserGroupReconciler.java [124:234]
private void modifyConfigMap (String name, String namespace) {
try {
boolean isAdded = false;
boolean isUpdated = false;
boolean isDeleted = false;
IamUserGroupCustomObject iamUserGroup = null;
String objKey = name.concat(namespace);
if (addedObjects.containsKey(objKey)) {
isAdded = true;
iamUserGroup = addedObjects.get(objKey);
addedObjects.remove(objKey);
}
else if (updatedObjects.containsKey(objKey)) {
isUpdated = true;
iamUserGroup = updatedObjects.get(objKey);
updatedObjects.remove(objKey);
}
else if (deletedObjects.containsKey(objKey)) {
isDeleted = true;
iamUserGroup = deletedObjects.get(objKey);
deletedObjects.remove(objKey);
}
V1ConfigMapList configMapList = apiConfigMap.list(namespace).getObject();
for (V1ConfigMap configMap : configMapList.getItems()) {
String configMapName = configMap.getMetadata().getName();
if (configMapName.equalsIgnoreCase(CONFIGMAP_NAME)) {
logger.info(String.format("Making changes to ConfigMap %s.%s to reflect IAM changes", configMapName, namespace));
//
// Retrieve the list of mappings under the "mapUsers" key of the "aws-auth" config map
// Note that even though the data section is provided as YAML in the K8s manifest, it is treated as a text blob
// Hence, we will have to use SnakeYaml to process this YAML string and extract a Map<String, Object> representation from it.
//
Map<String,Object> dataYml = parseYaml(configMap.getData());
List<Map<String,Object>> mapUsersList = (List<Map<String,Object>>) dataYml.get(MAPUSERS_KEY);
if (mapUsersList == null) mapUsersList = new ArrayList<Map<String,Object>>();
if (isAdded || isUpdated) {
//
// When a create event is triggered through IAM notification, the IamGroup custom object will contain only one group association for a user
// Hence, if there already is a mapping for the given user in the "aws-auth" config map, we will have to add the group(s) in the new IamGroup object to the existing group associations
//
String userToAdd = iamUserGroup.getSpec().getUsername();
Map<String, Object> mapToModify = null;
for (Map<String, Object> map : mapUsersList) {
if (map.get(USERNAME_FIELD).equals(userToAdd)) {
mapToModify = map;
break;
}
}
if (mapToModify != null) {
List<String> groups = (List<String>) mapToModify.get(GROUPS_FIELD);
groups.addAll(iamUserGroup.getSpec().getIamGroups());
} else {
IamUserGroup iamUser = new IamUserGroup();
iamUser.setUsername(iamUserGroup.getSpec().getUsername());
iamUser.setUserarn(iamUserGroup.getSpec().getIamUser());
iamUser.setGroups(iamUserGroup.getSpec().getIamGroups());
mapUsersList.add(iamUser.toMap());
dataYml.put(MAPUSERS_KEY, mapUsersList);
}
}
else if (isDeleted) {
//
// When a delete event is triggered through IAM notification, the IamGroup custom object will contain only one group association for a user.
// OTOH, when a delete event is triggered through "kubectl delete -f", it can contain multiple groups associations for a user.
// Hence, if there already is a mapping for the given user in the "aws-auth" config map, we will have to remove only the group(s) in the deleted IamGroup custom object from the existing group associations
//
String userToDelete = iamUserGroup.getSpec().getUsername();
Map<String,Object> mapToDelete = null;
for (Map<String, Object> map : mapUsersList) {
if (map.get(USERNAME_FIELD).equals(userToDelete)) {
mapToDelete = map;
break;
}
}
if (mapToDelete != null) {
List<String> groups = (List<String>) mapToDelete.get(GROUPS_FIELD);
groups.removeAll(iamUserGroup.getSpec().getIamGroups());
if (groups.isEmpty()) mapUsersList.remove(mapToDelete);
}
}
Yaml y = new Yaml ();
Map<String,String> newDataYaml = new HashMap<String,String>();
for (String key : dataYml.keySet()) {
newDataYaml.put(key, y.dump(dataYml.get(key)));
}
V1ConfigMap newConfigMap = new V1ConfigMapBuilder()
.withNewMetadata()
.withName(configMapName)
.withNamespace(namespace)
.endMetadata()
.addToData(newDataYaml)
.build();
newConfigMap = apiConfigMap.update(newConfigMap).getObject();
logger.info(String.format("Updated the ConfigMap %s.%s with resource version %s",
configMapName,
namespace,
newConfigMap.getMetadata().getResourceVersion()));
}
}
} catch (IOException e) {
logger.error(String.format("IOException occured when updarting ConfigMap '%s.%s'", name, namespace));
} catch (Exception e) {
logger.error(String.format("Exception occured when updating ConfigMap '%s.%s'; %s", name, namespace, e.getMessage()), e);
}
}