private void modifyConfigMap()

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);
		}
	}