/**
* 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.test.database;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.francetelecom.clara.cloud.commons.TechnicalException;
import com.orange.clara.cloud.dbaas.wsdl.data.CreateDatabaseResponseObject;
import com.orange.clara.cloud.dbaas.wsdl.data.DatabaseUserInfo;
import com.orange.clara.cloud.dbaas.wsdl.data.JobInfo;
import com.orange.clara.cloud.dbaas.wsdl.data.JobMessage;
import com.orange.clara.cloud.dbaas.wsdl.enumeration.BackupPlanWsEnum;
import com.orange.clara.cloud.dbaas.wsdl.enumeration.DatabaseUserTypeWsEnum;
import com.orange.clara.cloud.dbaas.wsdl.enumeration.EngineWsEnum;
import com.orange.clara.cloud.dbaas.wsdl.enumeration.JobStateWsEnum;
import com.orange.clara.cloud.dbaas.wsdl.enumeration.NetworkZoneWsEnum;
import com.orange.clara.cloud.dbaas.wsdl.enumeration.ServiceClassWsEnum;
import com.orange.clara.cloud.dbaas.wsdl.enumeration.SloWsEnum;
import com.orange.clara.cloud.dbaas.wsdl.enumeration.UsageWsEnum;
import com.orange.clara.cloud.dbaas.wsdl.response.DescribeDatabaseResponse;
import com.orange.clara.cloud.dbaas.wsdl.service.DbaasApiRemote;
/**
* Simple facade to dbaas service
* Only create and delete operations used to create a database for test are implemented
*/
public class DbaasService {
private static Logger logger = LoggerFactory.getLogger(DbaasService.class.getName());
/**
* dbaas url, usernamme, password and group name
*/
String dbaasUrl;
String dbaasUsername;
String dbaasPassword;
String dbaasGroupName = "elpaaso";
/**
* timeout to be used before considering that a dbaas operation timed-out
*/
long dbaasTimeout = 300000;
/**
* Webservice stub
*/
DbaasApiRemote dbaasStub;
/**
* Random generator used to generate database name
*/
Random randomGenerator = new Random();
/**
* @return dbaasUrl property
*/
public String getDbaasUrl() {
return dbaasUrl;
}
/**
* set dbaasUrl property
*/
public void setDbaasUrl(String dbaasUrl) {
this.dbaasUrl = dbaasUrl;
}
/**
* @return dbaasUsername property
*/
public String getDbaasUsername() {
return dbaasUsername;
}
/**
* set dbaasUsername property
*/
public void setDbaasUsername(String dbaasUsername) {
this.dbaasUsername = dbaasUsername;
}
/**
* @return dbaasPassword property
*/
public String getDbaasPassword() {
return dbaasPassword;
}
/**
* set dbaasPassword property
*/
public void setDbaasPassword(String dbaasPassword) {
this.dbaasPassword = dbaasPassword;
}
public String getDbaasGroupName() {
return dbaasGroupName;
}
public void setDbaasGroupName(String dbaasGroupName) {
this.dbaasGroupName = dbaasGroupName;
}
/**
* @return dbaasStub (dbaas webservice stub) property
*/
public DbaasApiRemote getDbaasStub() {
return dbaasStub;
}
/**
* set dbaasStub (dbaas webservice stub) property
*/
public void setDbaasStub(DbaasApiRemote dbaasStub) {
this.dbaasStub = dbaasStub;
}
/**
* @return dbaasTimeout property
*/
public long getDbaasTimeout() {
return dbaasTimeout;
}
/**
* set dbaasTimeout property
*/
public void setDbaasTimeout(long dbaasTimeout) {
this.dbaasTimeout = dbaasTimeout;
}
/**
* create dbaas web service stub
*/
private synchronized void createDbaasStub() {
logger.debug("Initializing DBaaS webservice stub");
JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
factoryBean.setServiceClass(DbaasApiRemote.class);
factoryBean.setAddress(dbaasUrl);
factoryBean.setPassword(dbaasPassword);
factoryBean.setUsername(dbaasUsername);
dbaasStub = factoryBean.create(DbaasApiRemote.class);
}
/**
* Request dbaas service to create a database corresponding to the DbaasDatabase database parameter The database host and host returned by dbaas service are
* updated on the database parameter The database name is generated and set on the database parameter if it was null
*
* @param database
*/
public void createDatabase(DbaasDatabase database) {
if(dbaasStub == null) createDbaasStub();
if (database.getHost() != null && database.getPort() != null) {
// Database is already created
return;
}
String name = database.getName();
if (name == null) logger.info("Database name is not set and will be generated by dbaas");
ServiceClassWsEnum serviceClass = ServiceClassWsEnum.XXXS;
int size = 1;
EngineWsEnum engine = database.getEngine();
String engineVersion = null; // use default
boolean autoUpgrade = true;
SloWsEnum slo = SloWsEnum.STANDARD;
boolean sox = false;
UsageWsEnum usage = UsageWsEnum.DEVTEST;
String datacenter = "Default";
NetworkZoneWsEnum networkZone = NetworkZoneWsEnum.RSC;
String dbSecurityGroup = "";
String databaseParametersSetName = "Default";
String maintenanceWindow = "Sun:20:00-04";
BackupPlanWsEnum backupPlan = BackupPlanWsEnum.NONE;
String backupWindow = "22:00-04";
String description = database.getDescription();
List<DatabaseUserInfo> users = new ArrayList<DatabaseUserInfo>();
DatabaseUserInfo user = new DatabaseUserInfo();
user.setLogin(database.getUser());
user.setPassword(database.getPassword());
user.setDatabaseUserType(DatabaseUserTypeWsEnum.OWNER);
users.add(user);
CreateDatabaseResponseObject taskObject = null; // do not use task id to check if creation is started
try {
logger.info("Creating database - " + " databaseName: " + name + " databaseUser: " + database.getUser() + " databasePassword: "
+ database.getPassword());
taskObject = dbaasStub.createDatabase(name, this.dbaasGroupName, size, serviceClass, engine, engineVersion, users, slo, sox, usage,
datacenter, networkZone, dbSecurityGroup, databaseParametersSetName, maintenanceWindow, backupPlan, backupWindow, autoUpgrade, description);
} catch(Exception e) {
throw new TechnicalException("dbaas failure " + e.getMessage(), e);
}
// Name was not set and has been generated by dbaas
if(name==null) {
logger.info("Database name generated by dbaas: " + taskObject.getDatabaseName());
database.setName(taskObject.getDatabaseName());
}
logger.info("Database UUId generated by dbaas: " + taskObject.getDatabaseUUId());
database.setUUId(taskObject.getDatabaseUUId());
// Wait for creation task to be completed
boolean databaseCreationFailure = true;
String databaseCreationErrorMessage = "Database creation timeout: database " + database.getName() + " still not created after "
+ this.getDbaasTimeout() / 1000 + " s";
boolean completed = false;
try {
long timeout = this.getDbaasTimeout();
long timeLimit = System.currentTimeMillis() + timeout;
while (!completed && System.currentTimeMillis() < timeLimit) {
JobStateWsEnum jobstate = dbaasStub.getJobState(taskObject.getJobId());
switch (jobstate) {
case FINISHED:
completed = true;
databaseCreationFailure = false;
break;
case CANCELLED:
case ERROR:
completed = true;
databaseCreationFailure = true;
JobInfo job = dbaasStub.getJob(taskObject.getJobId());
for (JobMessage message : job.getMessages()) {
databaseCreationErrorMessage += message.getMessage() + "\n";
}
break;
case PROCESSING:
case WAITING:
case SCHEDULED:
default:
long sleepTime = Math.min(5000, Math.max(0,(timeLimit-System.currentTimeMillis())));
logger.debug("Creating database " + database.getName() + "...");
Thread.sleep(sleepTime);
break;
}
}
} catch (Exception e) {
logger.error("dbaas failure: ", e.getMessage());
throw new TechnicalException("dbaas failure " + e.getMessage(), e);
}
// If creation job failed, throw an exception
if (databaseCreationFailure) {
logger.error(databaseCreationErrorMessage);
// Database creation not completed nor in error => timeout : try to delete it to avoid after resource leak
if(!completed) {
logger.info("request dbaas to delete database " + database.getName());
try {
dbaasStub.deleteDatabase(database.getUUId());
} catch(Exception e) {
logger.error("Exception while requesting dbaas to delete database " + database.getName() + ": " + e.getMessage(), e);
}
}
throw new TechnicalException(databaseCreationErrorMessage);
}
// Fetch database ip and port
try {
DescribeDatabaseResponse describeDatabase = dbaasStub.describeDatabase(database.getUUId());
database.setHost(describeDatabase.getEndPointFQDN());
database.setPort(describeDatabase.getEndPointTCPPort());
} catch (Exception e) {
logger.error("dbaas failure: ", e.getMessage());
throw new TechnicalException("dbaas failure " + e.getMessage(), e);
}
}
/**
* Request dbaas service to delete a database
*
* @param database
*/
public void deleteDatabase(DbaasDatabase database) {
if(dbaasStub == null) createDbaasStub();
String databaseUUId = database.getUUId();
if( database.getHost() == null || database.getPort() == null) {
logger.warn("database has not be created : host and/or port ar not set; delete operation is ignored");
return;
}
if (databaseUUId == null) {
throw new TechnicalException("databaseUUId is a required parameter");
}
logger.info("Deleting database - databaseUUId: " + databaseUUId);
boolean dbaasFailure = true;
String dbaasErrorMessage = "Database delete timeout";
try {
int jobId = dbaasStub.deleteDatabase(databaseUUId);
boolean completed = false;
long timeout = getDbaasTimeout();
long timeLimit = System.currentTimeMillis()+timeout;
while (!completed && System.currentTimeMillis() < timeLimit) {
JobStateWsEnum jobState = dbaasStub.getJobState(jobId);
switch (jobState) {
case FINISHED:
completed = true;
dbaasFailure = false;
break;
case CANCELLED:
case ERROR:
completed = true;
dbaasFailure = true;
dbaasErrorMessage = "";
JobInfo job = dbaasStub.getJob(jobId);
for (JobMessage message : job.getMessages()) {
dbaasErrorMessage += message.getMessage() + "\n";
}
break;
case PROCESSING:
case WAITING:
case SCHEDULED:
default:
logger.debug("Deleting database " + database.getName() + "...");
long sleepTime = Math.min(5000, (timeLimit-System.currentTimeMillis()));
Thread.sleep(sleepTime);
break;
}
}
} catch (Exception e) {
logger.error("unable to delete database "+e.getMessage());
throw new TechnicalException("Unable to delete database", e);
}
if(dbaasFailure) {
logger.error(dbaasErrorMessage);
throw new TechnicalException(dbaasErrorMessage);
}
// Set database object as deleted
database.setDeleted(true);
}
}