/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.systemservices.impl.security;
import com.emc.storageos.coordinator.client.model.Constants;
import com.emc.storageos.coordinator.client.service.DrUtil;
import com.emc.storageos.coordinator.common.Configuration;
import com.emc.storageos.db.common.DbConfigConstants;
import com.emc.storageos.security.ipsec.IPsecConfig;
import com.emc.storageos.svcs.errorhandling.resources.ServiceUnavailableException;
import com.emc.storageos.systemservices.impl.ipsec.IPsecManager;
import com.emc.storageos.systemservices.impl.property.Notifier;
import com.emc.storageos.systemservices.impl.upgrade.CoordinatorClientExt;
import com.emc.storageos.systemservices.impl.upgrade.LocalRepository;
import com.sun.corba.se.spi.resolver.LocalResolver;
import org.apache.commons.lang.StringUtils;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SecretsInit implements Runnable {
private static final Logger log = LoggerFactory.getLogger(SecretsInit.class);
private IPsecManager ipsecMgr;
private CoordinatorClientExt coordinator;
private IPsecConfig ipsecConfig;
private DrUtil drUtil;
private String ipsecLock = "ipseclock";
private int IPSEC_ROTATION_RETRY_INTERVAL = 10; //seconds
@Override
public void run() {
boolean ipsecInitDone = false;
while (!dbInitDone()) {
try {
log.info("Db init has not started. Waiting {} seconds", IPSEC_ROTATION_RETRY_INTERVAL);
Thread.sleep(IPSEC_ROTATION_RETRY_INTERVAL * 1000);
} catch (InterruptedException e) {
log.warn("Interrupted IPSec initialization.", e);
}
}
log.info("Db init done. Start ipsec init");
while (true) {
ipsecInitDone = rotateIPsecKey();
if (ipsecInitDone) {
return;
}
try {
log.info("sleep for " + IPSEC_ROTATION_RETRY_INTERVAL + " seconds before retrying ipsec rotation.");
Thread.sleep(IPSEC_ROTATION_RETRY_INTERVAL * 1000);
} catch (InterruptedException iex) {
log.warn("interrupted ipsec initial ");
}
}
}
private boolean dbInitDone() {
return checkDbInitDone(Constants.DBSVC_NAME) && checkDbInitDone(Constants.GEODBSVC_NAME);
}
private boolean checkDbInitDone(String dbsvcName) {
int nodeCount = coordinator.getNodeCount();
int doneCount = 0;
String dbVersion = coordinator.getCurrentDbSchemaVersion();
String configIdPrefix = Constants.GEODBSVC_NAME.equalsIgnoreCase(dbsvcName) ? "geodb" : "db";
log.info("Checking db init status for {} on {} nodes", dbsvcName, nodeCount);
for (int i = 1; i <= nodeCount; i++) {
String dbConfigId = String.format("%s-%d", configIdPrefix, i);
String configKind = coordinator.getCoordinatorClient().getVersionedDbConfigPath(dbsvcName, dbVersion);
Configuration config = coordinator.getCoordinatorClient().queryConfiguration(
coordinator.getCoordinatorClient().getSiteId(), configKind, dbConfigId);
if (config == null) {
return false;
}
String initDoneStr = config.getConfig(DbConfigConstants.INIT_DONE);
if (initDoneStr != null && initDoneStr.equals("true")) {
doneCount ++;
log.info("{}-{} init is done.", dbsvcName, i);
}
}
return doneCount == nodeCount;
}
private boolean rotateIPsecKey() {
InterProcessLock lock = null;
try {
if (drUtil.isMultivdc()) {
log.info("Skip ipsec key initial rotation for multi-vdc configuration");
return true;
}
if (drUtil.isMultisite()) {
log.info("Skip ipsec key initial rotation for multi-site DR configuration");
return true;
}
String preSharedKey = ipsecConfig.getPreSharedKeyFromZK();
if (!StringUtils.isBlank(preSharedKey)) {
log.info("IPsec key has been initialized");
return true;
}
lock = coordinator.getCoordinatorClient().getSiteLocalLock(ipsecLock);
lock.acquire();
log.info("Acquired the lock {}", ipsecLock);
preSharedKey = ipsecConfig.getPreSharedKeyFromZK();
if (!StringUtils.isBlank(preSharedKey)) {
log.info("IPsec key has been initialized. No need to regenerate it");
return true;
}
if (drUtil.isAllSitesStable()) {
log.info("No pre shared key in zk, generate a new key");
ipsecMgr.rotateKey(true);
return true;
}
return false;
} catch (ServiceUnavailableException suex) {
log.warn("cluster is not stable currently.");
return false;
} catch (Exception ex) {
log.warn("error when run ipsec initial rotation: ", ex);
return false;
} finally {
try {
if (lock != null) {
lock.release();
log.info("Released the lock {}", ipsecLock);
}
} catch (Exception ex) {
log.warn("error in releasing the lock {}", ipsecLock);
}
}
}
public IPsecConfig getIpsecConfig() {
return ipsecConfig;
}
public void setIpsecConfig(IPsecConfig ipsecConfig) {
this.ipsecConfig = ipsecConfig;
}
public CoordinatorClientExt getCoordinator() {
return coordinator;
}
public void setCoordinator(CoordinatorClientExt coordinator) {
this.coordinator = coordinator;
}
public IPsecManager getIpsecMgr() {
return ipsecMgr;
}
public void setIpsecMgr(IPsecManager ipsecMgr) {
this.ipsecMgr = ipsecMgr;
}
public DrUtil getDrUtil() {
return drUtil;
}
public void setDrUtil(DrUtil drUtil) {
this.drUtil = drUtil;
}
}