/***************************************************************************
* Copyright (c) 2015 VMware, Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package com.vmware.bdd.service.impl;
import com.vmware.aurora.global.Configuration;
import com.vmware.bdd.aop.annotation.ClusterEntityConcurrentWriteLock;
import com.vmware.bdd.aop.annotation.RetryTransaction;
import com.vmware.bdd.apitypes.ClusterStatus;
import com.vmware.bdd.apitypes.NodeRead;
import com.vmware.bdd.apitypes.NodeStatus;
import com.vmware.bdd.entity.ClusterEntity;
import com.vmware.bdd.entity.NodeEntity;
import com.vmware.bdd.manager.concurrent.AsyncExecutors;
import com.vmware.bdd.manager.intf.IClusterEntityManager;
import com.vmware.bdd.utils.Constants;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* Created by xiaoliangl on 9/8/15.
*/
@Component
public class ClusterSyncService {
private static final Logger logger = Logger.getLogger(ClusterSyncService.class);
private final long MAX_WAIT = Configuration.getLong(Constants.CLUSTER_SYNC_MAX_WAIT_SEC, 5*60*1000);
private final long TIME_SLICE = 100l;
@Autowired
private IClusterEntityManager clusterEntityMgr;
@Autowired
private NodeSyncService nodeSyncService;
public void syncUp(String clusterName, boolean updateClusterStatus) {
if (logger.isDebugEnabled()) {
logger.debug("start to sync cluster: " + clusterName);
}
List<NodeEntity> nodes = clusterEntityMgr.findAllNodes(clusterName);
boolean allNodesDown = true;
List<Future<NodeRead>> refreshedNodeList = new ArrayList<>();
for (NodeEntity node : nodes) {
refreshedNodeList.add(nodeSyncService.asyncRefreshNodeStatus(node.getVmName()));
}
//wait all node refresh is done
long elapsed = 0l;
while (CollectionUtils.isNotEmpty(refreshedNodeList)) {
for (Iterator<Future<NodeRead>> futureItr = refreshedNodeList.iterator(); futureItr.hasNext(); ) {
Future<NodeRead> refreshedNodeFuture = futureItr.next();
if(refreshedNodeFuture.isDone()) {
try {
NodeRead refreshedNode = refreshedNodeFuture.get();
if (logger.isDebugEnabled()) {
logger.debug("got sync node result: " + refreshedNode.getName());
}
if (NodeStatus.fromString(refreshedNode.getStatus()).ordinal() >= NodeStatus.POWERED_ON.ordinal()) {
allNodesDown = false;
}
} catch (InterruptedException e) {
logger.error("failed to get async refresh node result", e);
} catch (ExecutionException e) {
logger.error("failed to get async refresh node result", e);
} finally {
futureItr.remove();
}
}
}
try {
Thread.sleep(TIME_SLICE);
elapsed += TIME_SLICE;
if(elapsed >= MAX_WAIT) {
break;
}
} catch (InterruptedException e) {
//nothing to do
}
if(logger.isDebugEnabled()) {
logger.debug("sync cluster: " + clusterName);
}
}
if(CollectionUtils.isNotEmpty(refreshedNodeList)) {
logger.warn("failed to sync all nodes status in given time interval: " + clusterName);
} else {
logger.info(String.format("sync all node status of cluster: %1s in %2s milliseconds", clusterName, elapsed));
}
if (updateClusterStatus && allNodesDown) {
ClusterEntity cluster = clusterEntityMgr.findByName(clusterName);
if (cluster.getStatus() == ClusterStatus.RUNNING) {
logger.info("All nodes are powered off, switch cluster status to stopped.");
cluster.setStatus(ClusterStatus.STOPPED);
}
}
}
}