/** * Copyright (C) 2015 Orange * 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 * http://www.apache.org/licenses/LICENSE-2.0 * 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.francetelecom.clara.cloud.activation.plugin.cf.infrastructure; import com.francetelecom.clara.cloud.activation.plugin.cf.domain.AppActivationService; import com.francetelecom.clara.cloud.activation.plugin.cf.domain.CfTaskStatus; import com.francetelecom.clara.cloud.commons.TechnicalException; import com.francetelecom.clara.cloud.commons.tasks.Started; import com.francetelecom.clara.cloud.commons.tasks.TaskStatus; import com.francetelecom.clara.cloud.techmodel.cf.App; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.List; import java.util.UUID; @Service public class AppActivationServiceDefaultImpl implements AppActivationService { private static Logger LOGGER = LoggerFactory.getLogger(AppActivationServiceDefaultImpl.class.getName()); private CfAdapter cfAdapter; /** * in seconds */ @Value("${cf.appStartTimeoutS:600}") private int appStartTimeout; // initial value to ease unit // tests. Default value // assigned in spring config @Autowired public AppActivationServiceDefaultImpl(CfAdapter cfAdapter) { super(); this.cfAdapter = cfAdapter; } @Override public UUID activate(final App app) { return cfAdapter.createApp(app, app.getSpace().getValue()); } @Override public TaskStatus start(final App app) { final TaskStatus status = new Started("starting cloud foundry app <" + app.getAppName() + ">"); try { TaskStatus appSubStatus = new CfTaskStatus(System.currentTimeMillis(), app.getAppName(), app.getInstanceCount(), app.getSpace().getValue()); status.addSubtask(appSubStatus); if (cfAdapter.isAppStarted(app.getAppName(), app.getSpace().getValue())) { LOGGER.warn("will not start app<" + app.getAppName() + ">. app is already started."); status.setAsFinishedOk(); } else { cfAdapter.startApp(app, app.getSpace().getValue()); } } catch (Exception e) { String message = "unable to start app<" + app + ">. " + e.getMessage(); LOGGER.error(message, e); status.setAsFinishedFailed(message); } return status; } @Override public void stop(final App app) { if (cfAdapter.isAppStopped(app.getAppName(), app.getSpace().getValue())) { LOGGER.warn("will not stop app<" + app.getAppName() + ">. app is already stopped."); } else { cfAdapter.stopApp(app, app.getSpace().getValue()); } } @Override public void delete(final App app) { if (!cfAdapter.appExists(app.getAppName(), app.getSpace().getValue())) { LOGGER.warn("will not delete app<" + app.getAppName() + ">. app is already deleted."); } else { cfAdapter.logAppDiagnostics(app.getAppName(), app.getSpace().getValue()); cfAdapter.deleteApp(app, app.getSpace().getValue()); } } @Override public TaskStatus getAppStatus(TaskStatus taskStatus) { List<TaskStatus> appSubTasks = taskStatus.listSubtasks(); for (TaskStatus subTask : appSubTasks) { CfTaskStatus cfAppTaskStatus = (CfTaskStatus) subTask; String appName = cfAppTaskStatus.getAppName(); int instanceCounts = cfAppTaskStatus.getInstanceCounts(); String spaceName = cfAppTaskStatus.getSpaceName(); try { boolean appStartedProperly; int nbPeeks = cfAppTaskStatus.incrNbPeeks(); cfAppTaskStatus.setPercent(100 * nbStartedInstances(appName, instanceCounts, spaceName) / instanceCounts); appStartedProperly = (nbStartedInstances(appName, instanceCounts, spaceName) == instanceCounts); if (!appStartedProperly) { long elapsed = System.currentTimeMillis() - cfAppTaskStatus.getStartTime(); if (elapsed > 1000L * (long) appStartTimeout) { String msg = "timeout waiting for app " + appName + " to start: polled " + nbPeeks + " times and waited " + elapsed / 1000 + " s (max is:" + appStartTimeout + " s)"; cfAdapter.logAppDiagnostics(appName, spaceName); LOGGER.info(msg); cfAppTaskStatus.setAsFinishedFailed(msg); } } if (appStartedProperly) { LOGGER.info("all " + instanceCounts + " instance(s) of " + appName + " have properly started"); cfAppTaskStatus.setAsFinishedOk(); } } catch (Exception e) { throw new TechnicalException("unable to start app:" + appName + " caught:" + e, e); } } return new TaskStatus(taskStatus, new TaskStatus.SubTaskFactory() { @Override public TaskStatus createSubTask(TaskStatus subtask) { CfTaskStatus original = (CfTaskStatus) subtask; CfTaskStatus clone = new CfTaskStatus(original, original.getAppName(), original.getSpaceName(), original.getInstanceCounts(), original.getNbPeeks()); return clone; } }); // convention to return a copy that will be serialied and stored } private int nbStartedInstances(String appName, int instanceCounts, String spaceName) { return cfAdapter.peekAppStartStatus(instanceCounts, appName, spaceName); } public void setAppStartTimeout(int appStartTimeout) { this.appStartTimeout = appStartTimeout; } }