/*
* Copyright (c) 2017 Dell EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.db.client.upgrade.callbacks;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.Host;
import com.emc.storageos.db.client.model.ScopedLabel;
import com.emc.storageos.db.client.model.ScopedLabelSet;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;
import com.google.common.collect.Maps;
/**
* Migration handler to tag compute boot volumes from previous releases.
*
*/
public class VolumeBootVolumeMigration extends BaseCustomMigrationCallback {
private static final Logger log = LoggerFactory.getLogger(VolumeBootVolumeMigration.class);
private static String ISA_NAMESPACE = "vipr";
private static String BOOT_VOLUME = fqnName(ISA_NAMESPACE, "bootVolume");
private static Pattern MACHINE_TAG_REGEX = Pattern.compile("([^W]*\\:[^W]*)=(.*)");
private static String fqnName(String namespace, String name) {
return namespace + ":" + name;
}
public static String getBootVolumeTagName() {
return BOOT_VOLUME;
}
/**
* Return true of false if a given volume is a boot volume for an OS.
*
* @param blockObject to validate
* @return true or false if the volume is a boot volume
*/
private boolean isVolumeBootVolume(Volume volume) {
if (volume != null) {
Map<String, String> parsedTags = parseMachineTags(volume.getTag());
for (String tag : parsedTags.keySet()) {
if (tag != null && tag.startsWith(getBootVolumeTagName())) {
return true;
}
}
}
return false;
}
/**
* Parse machine tags
*
* @param tags tags to decipher
* @return a map of tags to values
*/
private Map<String, String> parseMachineTags(ScopedLabelSet tagSet) {
Map<String, String> machineTags = Maps.newHashMap();
if (tagSet != null) {
for (ScopedLabel tag : tagSet) {
Matcher matcher = MACHINE_TAG_REGEX.matcher(tag.getScope());
if (matcher.matches()) {
machineTags.put(matcher.group(1), matcher.group(2));
}
}
}
return machineTags;
}
@Override
public void process() throws MigrationCallbackException {
tagBootVolumes();
}
/**
* For all volumes, fill in the boot volume tag, if certain loose criteria is met
*/
private void tagBootVolumes() {
log.info("Updating volumes to contain boot tag.");
DbClient dbClient = this.getDbClient();
List<URI> hostURIs = dbClient.queryByType(Host.class, false);
Iterator<Host> hosts =
dbClient.queryIterativeObjects(Host.class, hostURIs);
while (hosts.hasNext()) {
Host host = hosts.next();
log.info("Examining Host (id={}) for boot volume upgrade", host.getId().toString());
// If there's no boot volume, there's nothing to upgrade.
if (NullColumnValueGetter.isNullURI(host.getBootVolumeId())) {
continue;
}
Volume volume = dbClient.queryObject(Volume.class, host.getBootVolumeId());
// if it's not in the DB, set it back to "null" on the host
if (volume == null) {
host.setBootVolumeId(NullColumnValueGetter.getNullURI());
dbClient.updateObject(host);
continue;
}
// If it's already a boot volume, move on
if (isVolumeBootVolume(volume)) {
continue;
}
// Add the tag.
ScopedLabelSet tagSet = volume.getTag();
if (tagSet == null) {
tagSet = new ScopedLabelSet();
volume.setTag(tagSet);
}
// Drop the new tag in the tag list
ScopedLabel tagLabel = new ScopedLabel(volume.getTenant().getURI().toString(), getBootVolumeTagName() + "=" + host.getId());
tagSet.add(tagLabel);
// Update the volume object
dbClient.updateObject(volume);
}
}
}