/**
* 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.scalability.helper;
import com.francetelecom.clara.cloud.commons.BusinessException;
import com.francetelecom.clara.cloud.commons.InvalidMavenReferenceException;
import com.francetelecom.clara.cloud.commons.MavenReference;
import com.francetelecom.clara.cloud.commons.TechnicalException;
import com.francetelecom.clara.cloud.core.service.ManageApplication;
import com.francetelecom.clara.cloud.core.service.ManageApplicationRelease;
import com.francetelecom.clara.cloud.core.service.ManageEnvironment;
import com.francetelecom.clara.cloud.core.service.ManagePaasUser;
import com.francetelecom.clara.cloud.core.service.exception.*;
import com.francetelecom.clara.cloud.coremodel.*;
import com.francetelecom.clara.cloud.deployment.logical.service.ManageLogicalDeployment;
import com.francetelecom.clara.cloud.logicalmodel.*;
import com.francetelecom.clara.cloud.logicalmodel.samplecatalog.SampleAppProperties;
import com.francetelecom.clara.cloud.services.dto.EnvironmentDto;
import com.francetelecom.clara.cloud.services.dto.EnvironmentDto.EnvironmentStatusEnum;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import java.net.MalformedURLException;
import java.util.*;
/**
* ScalabilityHelper Class used to create set of user data Sample usage : cf.
* ManageScalabilityImplTest
*
* @author Clara
*/
public class ScalabilityHelper {
/**
* Logger
*/
private static final transient org.slf4j.Logger logger = LoggerFactory.getLogger(ScalabilityHelper.class);
private static final EnvironmentDto.EnvironmentTypeEnum DEFAULT_ENV_TYPE = EnvironmentDto.EnvironmentTypeEnum.DEVELOPMENT;
private static final String LETTER_GUI = "G";
private static final String LETTER_NODE = "N";
private static final String LETTER_DATABASE = "D";
private static final String LETTER_STORE = "S";
/**
* paas managers
*/
private final ManagePaasUser managePaasUser;
private final ManageApplication manageApplication;
private final ManageApplicationRelease manageApplicationRelease;
private final ManageLogicalDeployment manageLogicalDeployment;
private final ManageEnvironment manageEnvironment;
private final SampleAppProperties sampleAppProperties;
private final boolean isFakeWorld;
/**
* scalability functions manager are provided by impl or mocks bean context
*
* @param managePaasUser
* paas user
* @param manageApplication
* app manager
* @param manageApplicationRelease
* appRelease manager
* @param manageLogicalDeployment
* ld manager
* @param manageEnvironment
* env manager
* @param sampleAppProperties
* app properties
* @param isFakeWorld
* must be true on mocked env or when incomplete activation plugin found this arg will determine if we skip environment creation
*/
public ScalabilityHelper(ManagePaasUser managePaasUser, ManageApplication manageApplication, ManageApplicationRelease manageApplicationRelease,
ManageLogicalDeployment manageLogicalDeployment, ManageEnvironment manageEnvironment, SampleAppProperties sampleAppProperties, boolean isFakeWorld) {
this.managePaasUser = managePaasUser;
this.manageApplication = manageApplication;
this.manageApplicationRelease = manageApplicationRelease;
this.manageLogicalDeployment = manageLogicalDeployment;
this.manageEnvironment = manageEnvironment;
this.sampleAppProperties = sampleAppProperties;
this.isFakeWorld = isFakeWorld;
}
public void razData(boolean activationIsAvailable) throws BusinessException {
Collection<Application> apps = manageApplication.findApplications();
if (apps != null && apps.size() > 0) {
logger.debug("remove {} apps", apps.size());
for (Application app : apps) {
try {
List<ApplicationRelease> applicationReleases = manageApplicationRelease.findApplicationReleasesByAppUID(app.getUID());
logger.debug("remove app {} releases", applicationReleases.size());
for (ApplicationRelease ar : applicationReleases) {
List<EnvironmentDto> allAREnvironments = manageEnvironment.findEnvironmentsByAppRelease(ar.getUID());
logger.debug("remove app {} envs", allAREnvironments.size());
for (EnvironmentDto env : allAREnvironments) {
String envName = env.getUid();
logger.debug("remove env '{}'", envName);
if (activationIsAvailable) {
manageEnvironment.deleteEnvironment(envName);
logger.debug("wait env '{}' to be removed", envName);
waitForStatus(envName, EnvironmentStatusEnum.REMOVED);
} else {
manageEnvironment.forceStatusForAndEnvironment(envName, EnvironmentStatus.REMOVED);
}
logger.debug("purge env '{}'", envName);
manageEnvironment.purgeRemovedEnvironment(envName);
}
logger.debug("purge release '{}'", ar.getUID());
manageApplicationRelease.deleteAndPurgeApplicationRelease(ar.getUID());
}
manageApplication.purgeApplication(app.getUID());
} catch (ObjectNotFoundException onfe) {
logger.warn(onfe.getMessage());
}
}
logger.info("remove users");
try {
List<PaasUser> users = managePaasUser.findAllPaasUsers();
if (users != null) {
for (PaasUser usr : users) {
managePaasUser.deletePaasUser(usr.getId());
}
}
} catch (ObjectNotFoundException onfe) {
logger.warn(onfe.getMessage());
}
}
}
private void waitForStatus(String environmentId, EnvironmentStatusEnum expectedStatus) throws ObjectNotFoundException {
int timeoutInMinutes = 60;
long timeoutMs = System.currentTimeMillis() + timeoutInMinutes * 60 * 1000;
EnvironmentDto envDto = manageEnvironment.findEnvironmentByUID(environmentId);
EnvironmentStatusEnum actualStatus = envDto.getStatus();
logger.debug("wait for status {}, currently {}", expectedStatus.toString(), actualStatus.toString());
while (expectedStatus != actualStatus) {
if (!actualStatus.toString().endsWith("ING")
&& actualStatus != EnvironmentStatusEnum.RUNNING) {
// In a final step, will not change until an action is requested
throw new TechnicalException("Activation process failed : " + envDto.getStatusMessage() + " status=" + actualStatus);
}
if (System.currentTimeMillis() > timeoutMs) {
throw new TechnicalException("Activation process timeout: environment not " + expectedStatus + " after " + timeoutInMinutes + " minutes");
}
try {
Thread.sleep(2000);
logger.debug("wait for status {}, currently {}", expectedStatus.toString(), actualStatus.toString());
} catch (InterruptedException e) {
// ignore
}
envDto = manageEnvironment.findEnvironmentByUID(environmentId);
actualStatus = envDto.getStatus();
}
}
public Collection<PaasUser> createPaasUsers(String namePrefix, int nbToCreate) {
Collection<PaasUser> createdUsers = new ArrayList<PaasUser>();
for (int nbCreated = 0; nbCreated < nbToCreate; nbCreated++) {
String nameToUse = namePrefix + nbCreated;
if (nbCreated > 1) {
nameToUse += nbCreated;
}
PaasUser pUsr = new PaasUser(nameToUse, "aLastName", new SSOId(nameToUse), nameToUse+"@orange.com");
managePaasUser.checkBeforeCreatePaasUser(pUsr);
createdUsers.add(pUsr);
}
return createdUsers;
}
public Collection<PaasUser> createTeam(String namePrefix) {
Collection<PaasUser> createdUsers = new ArrayList<PaasUser>();
Collection<String> opsTeam = new ArrayList<String>();
opsTeam.add("Manager");
opsTeam.add("Architect");
opsTeam.add("QA");
opsTeam.add("Dev1");
opsTeam.add("Dev2");
int i=0;
for (String name : opsTeam) {
String nameToUse = namePrefix + "." + name;
PaasUser pUsr = new PaasUser(nameToUse,nameToUse,new SSOId("ssoid"+i++),nameToUse + "." + nameToUse + "@orange.com");
managePaasUser.checkBeforeCreatePaasUser(pUsr);
createdUsers.add(pUsr);
}
return createdUsers;
}
private Application appFactory(String appLabel, String appCode, PaasUser author) throws DuplicateApplicationException, ApplicationNotFoundException, PaasUserNotFoundException {
logger.debug("appFactory({})", appLabel);
long start = System.currentTimeMillis();
String appUid = manageApplication.createPublicApplication(appCode, appLabel, "demo application " + appLabel, null, author.getSsoId());
Application demoApp = manageApplication.findApplicationByUID(appUid);
logger.debug("STATS createApplication duration: " + (System.currentTimeMillis() - start) + "ms");
return demoApp;
}
private ApplicationRelease releaseFactory(PaasUser author, Application app, String releaseVersion) throws MalformedURLException, ObjectNotFoundException,
DuplicateApplicationReleaseException {
// ApplicationRelease demoAppRelease = new ApplicationRelease(app,
// releaseVersion);
// demoAppRelease.setReleaseVersion(releaseVersion);
long start = System.currentTimeMillis();
String releaseUid = manageApplicationRelease.createApplicationRelease(app.getUID(), author.getSsoId().getValue(), releaseVersion);
ApplicationRelease demoAppRelease = manageApplicationRelease.findApplicationReleaseByUID(releaseUid);
demoAppRelease.setDescription("Scalability demo application - initial release");
demoAppRelease = manageApplicationRelease.updateApplicationRelease(demoAppRelease);
logger.debug("STATS createApplicationRelease duration: " + (System.currentTimeMillis() - start) + "ms");
return demoAppRelease;
}
private void logicalModelFactory(ApplicationRelease appRelease, String logicalModelPattern) throws ObjectNotFoundException, InvalidMavenReferenceException {
String releaseName = appRelease.getUID();
// CREATE SPRINGOO LOGICAL MODEL
LogicalDeployment ld = manageLogicalDeployment.findLogicalDeployment(appRelease.getLogicalDeployment().getId());
int nbGui = StringUtils.countMatches(logicalModelPattern, LETTER_GUI);
int nbDB = StringUtils.countMatches(logicalModelPattern, LETTER_DATABASE);
int nbStore = StringUtils.countMatches(logicalModelPattern, LETTER_STORE);
int nbNode = StringUtils.countMatches(logicalModelPattern, LETTER_NODE);
logger.debug("logicalModelFactory {} ", releaseName);
Collection<LogicalWebGUIService> guis = new ArrayList<LogicalWebGUIService>();
Collection<LogicalRelationalService> dbs = new ArrayList<LogicalRelationalService>();
Collection<LogicalOnlineStorageService> stores = new ArrayList<LogicalOnlineStorageService>();
Collection<ProcessingNode> nodes = new ArrayList<ProcessingNode>();
for (int g = 0; g < nbGui; g++) {
LogicalWebGUIService webGuiService = webGuiServiceFactory(releaseName + String.valueOf(g));
ld.addLogicalService(webGuiService);
guis.add(webGuiService);
}
for (int d = 0; d < nbDB; d++) {
LogicalRelationalService rdbService = relationalDBServiceFactory(releaseName + String.valueOf(d));
ld.addLogicalService(rdbService);
dbs.add(rdbService);
}
for (int s = 0; s < nbStore; s++) {
LogicalOnlineStorageService onlineStorageService = onlineStorageServiceFactory(releaseName + String.valueOf(s));
ld.addLogicalService(onlineStorageService);
stores.add(onlineStorageService);
}
Iterator<LogicalWebGUIService> itGuis = guis.iterator();
for (int n = 0; n < nbNode; n++) {
LogicalWebGUIService gui = null;
if (itGuis.hasNext()) {
gui = itGuis.next();
}
ProcessingNode lenService = cfJavaProcessingFactory(ld, releaseName + "Node." + n, gui, dbs, stores);
// ld.addExecutionNode(lenService);
nodes.add(lenService);
}
logger.debug("updateLogicalDeployment {}", ld.getName());
long start = System.currentTimeMillis();
try {
ld = manageLogicalDeployment.checkOverallConsistencyAndUpdateLogicalDeployment(ld);
} catch (BusinessException e) {
e.printStackTrace(); // To change body of catch statement use File |
// Settings | File Templates.
}
logger.debug("STATS updateLogicalDeployment duration: " + (System.currentTimeMillis() - start) + "ms");
}
/**
* Creates the environment if not in real world
*
* @param author
* env creation author
* @param appReleaseUid
* app release unique id
* @param envNumber
* id used to name env
* @return envOutputName
* @throws com.francetelecom.clara.cloud.core.service.exception.ObjectNotFoundException
*/
private String environmentFactory(PaasUser author, String appReleaseUid, int envNumber) throws BusinessException {
String environmentUid = "noenv";
if (this.isFakeWorld) {
String releaseName = appReleaseUid;
String envInputName = releaseName + "Env" + String.valueOf(envNumber);
long start = System.currentTimeMillis();
environmentUid = manageEnvironment.createEnvironment(appReleaseUid, DEFAULT_ENV_TYPE, author.getSsoId().getValue(), envInputName);
logger.debug("STATS createEnvironment duration: " + (System.currentTimeMillis() - start) + "ms");
logger.info("wait env '{}' to be created", environmentUid);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
} else {
logger.error("You are running scalability feature in a real world! Ignoring environment creation...");
}
return environmentUid;
}
/**
* WEB_GUI Service production
*
* @param releaseName
* @return
*/
private LogicalWebGUIService webGuiServiceFactory(String releaseName) {
LogicalWebGUIService lsWebUi = new LogicalWebGUIService();
lsWebUi.setLabel(releaseName + "WebUi");
lsWebUi.setContextRoot(new ContextRoot("/"));
lsWebUi.setSecure(false);
lsWebUi.setStateful(false);
return lsWebUi;
}
/**
* RelationalDB Service production
*
* @param releaseName
* @return
*/
private LogicalRelationalService relationalDBServiceFactory(String releaseName) {
LogicalRelationalService lsRelational = new LogicalRelationalService();
lsRelational.setLabel(releaseName + "DB");
lsRelational.setServiceName("postgres-db");
lsRelational.setCapacityMo(1000);
lsRelational.setMaxConnection(50);
lsRelational.setRelationalReplicaNumber(0);
lsRelational.setSqlVersion(LogicalRelationalServiceSqlDialectEnum.POSTGRESQL_DEFAULT);
// manageLogicalDeployment.updateLogicalDeployment(lsRelational);
return lsRelational;
}
/**
* Store service production
*
* @param releaseName
* @return
*/
private LogicalOnlineStorageService onlineStorageServiceFactory(String releaseName) {
LogicalOnlineStorageService lsOnline = new LogicalOnlineStorageService();
lsOnline.setLabel(releaseName + "eDB");
lsOnline.setServiceName("demo-edb");
lsOnline.setStorageCapacityMb(100);
return lsOnline;
}
/**
* Execution node production, including service associations.
*
* @param name
* @param gui
* @param dbs
* @param stores
* @return
*/
private ProcessingNode cfJavaProcessingFactory(LogicalDeployment ld, String name, LogicalWebGUIService gui,
Collection<LogicalRelationalService> dbs, Collection<LogicalOnlineStorageService> stores) {
// log only the first logical model
if (logger.isDebugEnabled()) {
String svc = (gui != null ? "1" + LETTER_GUI : "") + (dbs != null ? dbs.size() + LETTER_DATABASE : "")
+ (stores != null ? stores.size() + LETTER_STORE : "");
logger.debug("Create execution node {} with {}", name, svc);
}
ProcessingNode len = new CFJavaProcessing();
len.setLabel(name);
String appName = "cf-wicket-jpa";
String type = "war";
len.setSoftwareReference(sampleAppProperties.getMavenReference(appName, type));
MavenReference lenMr = len.getSoftwareReference();
assert (lenMr != null) : "maven reference should not be null ! for " + appName;
logger.debug("resolve execution node maven reference {}", lenMr.toString());
ld.addExecutionNode(len);
if (gui != null) {
// expecting a single execution node to be producing a webGUI
len.addLogicalServiceUsage(gui, LogicalServiceAccessTypeEnum.NOT_APPLICABLE);
}
// db services
if (dbs != null) {
for (LogicalRelationalService db : dbs) {
len.addLogicalServiceUsage(db, LogicalServiceAccessTypeEnum.READ_WRITE);
}
}
// store services
if (stores != null) {
for (LogicalOnlineStorageService store : stores) {
len.addLogicalServiceUsage(store, LogicalServiceAccessTypeEnum.READ_WRITE);
}
}
// deprecated ? // manageLogicalDeployment.resolveMavenURL(len);
return len;
}
/**
* @param author
* @param appName
* @param nbApp
* @param nbReleasePerApp
* @param logicalModelPattern
* @see com.francetelecom.clara.cloud.scalability.ManageScalability
* @return
* @throws com.francetelecom.clara.cloud.commons.BusinessException
*/
public Collection<ApplicationRelease> createApplications(PaasUser author, String appName, int nbApp, int nbReleasePerApp, String logicalModelPattern)
throws BusinessException {
Collection<ApplicationRelease> appReleases = new ArrayList<ApplicationRelease>();
try {
for (int i = 0; i < nbApp; i++) {
String appId;
String appCode;
Application demoApp;
appId = "CFWicketJPA" + UUID.randomUUID();
appCode = "CWJ" + UUID.randomUUID();
// *** create app
demoApp = appFactory(appId, appCode, author);
for (int j = 0; j < nbReleasePerApp; j++) {
String relMinorId = String.valueOf(j);
String releaseVersion = "G0R0C" + relMinorId;
// *** create app-release
ApplicationRelease demoAppRelease = releaseFactory(author, demoApp, releaseVersion);
// *** create logical models
logicalModelFactory(demoAppRelease, logicalModelPattern);
appReleases.add(demoAppRelease);
}
}
} catch (MalformedURLException mue) {
throw new BusinessException("incorrect URL : ",mue);
}
return appReleases;
}
public Application populateSimpleTestPhase(PaasUser author, boolean createEnv) throws BusinessException {
logger.info("populateSimpleTestPhase()");
int numberOfEnvironmentToCreate = 0;
if (createEnv) {
numberOfEnvironmentToCreate = 1;
}
Collection<ApplicationRelease> applicationReleases = populate("GND", "simpleTestPhase", 1, 1, numberOfEnvironmentToCreate);
ApplicationRelease firstApplicationRelease = applicationReleases.iterator().next();
return firstApplicationRelease.getApplication();
}
/**
* @param pattern a string that include :
* - 'G' to create a gui
* - 'N' to create an execution node,
* - 'D' to create a relational database
* - 'S' to create an online store
* @param teamName name of the set of sample users
* @param nbApp number of application to create
* @param nbReleasePerApp number of release per app to create
* @param nbEnvPerRelease number of environment per release to create
* @return
* @throws BusinessException
*/
public Collection<ApplicationRelease> populate(String pattern, String teamName, int nbApp, int nbReleasePerApp, int nbEnvPerRelease)
throws BusinessException {
// users
Collection<PaasUser> users = createTeam(teamName);
PaasUser author = users.iterator().next();
// app, releases, logicalmodel
Collection<ApplicationRelease> releases = createApplications(author, "App of " + teamName, nbApp, nbReleasePerApp, pattern);
// env
int resultAwaitingEnv = nbApp * nbReleasePerApp * nbEnvPerRelease;
logger.info("Populating " + resultAwaitingEnv + " environment(s)...");
for (ApplicationRelease release : releases) {
final String releaseUid = release.getUID();
for (int k = 0; k < nbEnvPerRelease; k++) {
environmentFactory(author, releaseUid, k);
}
}
return releases;
}
}