/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.validators.smis.common;
import com.emc.storageos.db.client.model.DiscoveredDataObject;
import com.emc.storageos.db.client.model.ExportMask;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.volumecontroller.impl.smis.CIMPropertyFactory;
import com.emc.storageos.volumecontroller.impl.validators.ValidatorLogger;
import com.emc.storageos.volumecontroller.impl.validators.smis.AbstractSMISValidator;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.cim.CIMInstance;
import javax.cim.CIMObjectPath;
import javax.wbem.CloseableIterator;
import javax.wbem.WBEMException;
import java.util.Collection;
import java.util.Set;
import static com.google.common.collect.Collections2.transform;
/**
* Abstract template class for comparing a set of ExportMask-related database values against hardware values.
* If any additional differences are detected on the hardware (i.e. SMI-S) side, then a validation error would be
* logged.
*/
public abstract class AbstractExportMaskValidator extends AbstractSMISValidator {
public static final String FIELD_INITIATORS = "initiators";
public static final String FIELD_VOLUMES = "volumes";
private static final Logger log = LoggerFactory.getLogger(AbstractExportMaskValidator.class);
private final StorageSystem storage;
private final ExportMask exportMask;
private final String field;
public AbstractExportMaskValidator(StorageSystem storage, ExportMask exportMask, String field) {
this.storage = storage;
this.exportMask = exportMask;
this.field = field;
}
@Override
public boolean validate() throws Exception {
log.info("Validating export mask: {}, field: {}", exportMask.getId(), field);
getLogger().setLog(log);
// We want the latest info, but in most customer cases, array configurations don't change every 5 minutes.
// By default we do not want to refresh and cause additional performance issues.
// But in the case of automated test suites where we combine in-controller and out-of-controller operations,
// we have tighter tolerances and need to run refresh.
if (getConfig().validationRefreshEnabled()) {
// Refresh the provider's view of the storage system
getEmcRefreshSystemInvoker().invoke(storage);
}
Set<String> database = getDatabaseResources();
Set<String> hardware = getHardwareResources();
log.info("Database has: {}", Joiner.on(",").join(database));
log.info("{} has: {}", storage.getSerialNumber(), Joiner.on(",").join(hardware));
// Get all items in hardware that are not contained in the database, i.e. resources unknown to the database.
Set<String> differences = Sets.difference(hardware, database);
for (String diff : differences) {
getLogger().logDiff(exportMask.getId().toString(), field, ValidatorLogger.NO_MATCHING_ENTRY, diff);
}
return true;
}
protected abstract String getAssociatorProperty();
protected abstract String getAssociatorClass();
protected abstract Function<? super String, String> getHardwareTransformer();
protected abstract Set<String> getDatabaseResources();
private Set<String> getHardwareResources() {
Set<String> hardware = Sets.newHashSet();
CloseableIterator<CIMInstance> associatedResources = null;
try {
CIMObjectPath maskingViewPath = getMaskingView();
String[] prop = new String[] { getAssociatorProperty() };
associatedResources = getHelper().getAssociatorInstances(storage, maskingViewPath, null, getAssociatorClass(), null, null,
prop);
while (associatedResources.hasNext()) {
CIMInstance cimInstance = associatedResources.next();
String assocProperty = CIMPropertyFactory.getPropertyValue(cimInstance, getAssociatorProperty());
hardware.add(assocProperty);
}
} catch (WBEMException wbeme) {
log.error("SMI-S failure", wbeme);
} finally {
if (associatedResources != null) {
try {
associatedResources.close();
} catch (Exception e) {
// ignore
}
}
}
Function<? super String, String> hardwareTransformer = getHardwareTransformer();
Collection<String> result = hardware;
if (hardwareTransformer != null) {
result = transform(hardware, getHardwareTransformer());
}
return Sets.newHashSet(result);
}
private CIMObjectPath getMaskingView() {
if (DiscoveredDataObject.Type.vmax.toString().equalsIgnoreCase(storage.getSystemType())) {
return getCimPath().getMaskingViewPath(storage, exportMask.getMaskName());
} else if (DiscoveredDataObject.Type.vnxblock.toString().equalsIgnoreCase(storage.getSystemType())) {
return getCimPath().getLunMaskingProtocolControllerPath(storage, exportMask);
}
throw new IllegalArgumentException(
String.format("Don't know how to get masking view for storage type: %s", storage.getSystemType()));
}
}