package de.cinovo.cloudconductor.server.web.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.core.MultivaluedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import de.cinovo.cloudconductor.api.ServiceState;
import de.cinovo.cloudconductor.api.model.TaskState;
import de.cinovo.cloudconductor.server.comparators.DefaultStateComparator;
import de.cinovo.cloudconductor.server.comparators.PackageVersionComparator;
import de.cinovo.cloudconductor.server.dao.IAgentOptionsDAO;
import de.cinovo.cloudconductor.server.dao.IHostDAO;
import de.cinovo.cloudconductor.server.dao.IPackageDAO;
import de.cinovo.cloudconductor.server.dao.IPackageServerDAO;
import de.cinovo.cloudconductor.server.dao.IPackageVersionDAO;
import de.cinovo.cloudconductor.server.dao.IServiceDAO;
import de.cinovo.cloudconductor.server.dao.IServiceDefaultStateDAO;
import de.cinovo.cloudconductor.server.dao.IServiceStateDAO;
import de.cinovo.cloudconductor.server.dao.ITemplateDAO;
import de.cinovo.cloudconductor.server.model.EAgentOption;
import de.cinovo.cloudconductor.server.model.EHost;
import de.cinovo.cloudconductor.server.model.EPackage;
import de.cinovo.cloudconductor.server.model.EPackageVersion;
import de.cinovo.cloudconductor.server.model.EService;
import de.cinovo.cloudconductor.server.model.EServiceDefaultState;
import de.cinovo.cloudconductor.server.model.EServiceState;
import de.cinovo.cloudconductor.server.model.ETemplate;
import de.cinovo.cloudconductor.server.util.exception.FormErrorException;
import de.cinovo.cloudconductor.server.web.CSViewModel;
import de.cinovo.cloudconductor.server.web.helper.AWebPage;
import de.cinovo.cloudconductor.server.web.helper.AjaxAnswer;
import de.cinovo.cloudconductor.server.web.helper.FormValidator;
import de.cinovo.cloudconductor.server.web.interfaces.ITemplate;
import de.cinovo.cloudconductor.server.web.interfaces.IWebPath;
import de.taimos.cxf_renderer.model.RenderedUI;
import de.taimos.restutils.RESTAssert;
/**
* Copyright 2014 Cinovo AG<br>
* <br>
*
* @author psigloch
*
*/
public class TemplatesImpl extends AWebPage implements ITemplate {
@Autowired
protected ITemplateDAO dTemplate;
@Autowired
private IPackageDAO dPkg;
@Autowired
private IServiceDefaultStateDAO dSvcDefState;
@Autowired
private IServiceStateDAO dSvcState;
@Autowired
private IPackageServerDAO dPackageServer;
@Autowired
private IServiceDAO dSvc;
@Autowired
private IPackageVersionDAO dPkgVersion;
@Autowired
protected IAgentOptionsDAO dAgentOptions;
@Autowired
protected IHostDAO dHosts;
@Override
protected String getTemplateFolder() {
return "templates";
}
@Override
protected void init() {
this.navRegistry.registerMainMenu(this.getNavElementName(), ITemplate.ROOT);
this.addBreadCrumb(IWebPath.WEBROOT + ITemplate.ROOT, this.getNavElementName());
this.addTopAction(IWebPath.WEBROOT + ITemplate.ROOT + IWebPath.ACTION_ADD, "Create new Template");
}
@Override
protected String getNavElementName() {
return "Templates";
}
@Override
@Transactional
public RenderedUI view() {
List<ETemplate> etemplates = this.dTemplate.findList();
List<String> updates = new ArrayList<>();
for (ETemplate t : etemplates) {
this.addSidebarElement(t.getName());
this.sortNamedList(t.getHosts());
Collections.sort(t.getPackageVersions(), new PackageVersionComparator());
// collect updateable packages
for (EPackageVersion pv : t.getPackageVersions()) {
List<EPackageVersion> versionsOfPackage = new ArrayList<>(pv.getPkg().getRPMs());
Collections.sort(versionsOfPackage, new PackageVersionComparator());
if (!versionsOfPackage.get(versionsOfPackage.size() - 1).equals(pv)) {
updates.add(pv.getName());
}
}
}
this.sortNamedList(etemplates);
CSViewModel view = this.createView();
view.addModel("TEMPLATES", etemplates);
view.addModel("UPDATE", updates);
return view.render();
}
@Override
@Transactional
public AjaxAnswer updatePackages(String tname, List<String> updatePackages) {
RESTAssert.assertNotEmpty(tname);
ETemplate template = this.dTemplate.findByName(tname);
if ((updatePackages == null) || updatePackages.isEmpty() || (template == null)) {
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
// delete old versions
Set<EPackageVersion> remove = new HashSet<>();
for (EPackageVersion installed : template.getPackageVersions()) {
if (updatePackages.contains(installed.getPkg().getName())) {
remove.add(installed);
}
}
template.getPackageVersions().removeAll(remove);
// add newest version
for (String pkg : updatePackages) {
EPackage ep = this.dPkg.findByName(pkg);
List<EPackageVersion> rpms = new ArrayList<>(ep.getRPMs());
Collections.sort(rpms, new PackageVersionComparator());
if (!template.getPackageVersions().contains(rpms.get(rpms.size() - 1))) {
template.getPackageVersions().add(rpms.get(rpms.size() - 1));
}
}
this.dTemplate.save(template);
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
@Override
@Transactional
public AjaxAnswer changeTemplateState(String tname, List<String> deletePackages) {
RESTAssert.assertNotEmpty(tname);
ETemplate template = this.dTemplate.findByName(tname);
if ((deletePackages == null) || deletePackages.isEmpty() || (template == null)) {
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
// delete packges from template
Set<EPackageVersion> remove = new HashSet<>();
for (EPackageVersion installed : template.getPackageVersions()) {
if (deletePackages.contains(installed.getPkg().getName())) {
remove.add(installed);
}
}
template.getPackageVersions().removeAll(remove);
// delete packages from default state
List<EServiceDefaultState> defaultStates = this.dSvcDefState.findByTemplate(tname);
for (EServiceDefaultState state : defaultStates) {
for (EPackage pkg : state.getService().getPackages()) {
if (deletePackages.contains(pkg.getName())) {
this.dSvcDefState.delete(state);
break;
}
}
}
// delete service state from hosts
for (EHost host : template.getHosts()) {
for (EServiceState service : host.getServices()) {
for (EPackage pkg : service.getService().getPackages()) {
if (deletePackages.contains(pkg.getName())) {
this.dSvcState.delete(service);
break;
}
}
}
}
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
@Override
@Transactional
public RenderedUI editTemplateView(String tname) {
RESTAssert.assertNotEmpty(tname);
ETemplate template = this.dTemplate.findByName(tname);
RESTAssert.assertNotNull(template);
final CSViewModel vm = this.createModal("mEditTemplate");
vm.addModel("template", template);
vm.addModel("availablePM", this.dPackageServer.findList());
return vm.render();
}
@Override
@Transactional
public AjaxAnswer editTemplate(String tname, String templatename, Long packageManagerId, String description, String autoupdate, String smoothupdate) throws FormErrorException {
RESTAssert.assertNotEmpty(tname);
this.templateOptionErrorHandling(templatename, packageManagerId, description, autoupdate, smoothupdate);
// save the new settings
ETemplate template = this.dTemplate.findByName(tname);
RESTAssert.assertNotNull(template);
template.setName(templatename);
template.setDescription(description);
template.setYum(this.dPackageServer.findById(packageManagerId));
template.setAutoUpdate(Boolean.valueOf(autoupdate));
template.setSmoothUpdate(Boolean.valueOf(smoothupdate));
this.dTemplate.save(template);
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
@Override
@Transactional
public RenderedUI addPackageView(String tname) {
RESTAssert.assertNotEmpty(tname);
ETemplate template = this.dTemplate.findByName(tname);
List<EPackage> pkgList = this.dPkg.findList();
for (EPackageVersion pv : template.getPackageVersions()) {
pkgList.remove(pv.getPkg());
}
this.sortNamedList(pkgList);
final CSViewModel vm = this.createModal("mAddPackage");
vm.addModel("template", template);
vm.addModel("packages", pkgList);
return vm.render();
}
@Override
@Transactional
public AjaxAnswer addPackage(String tname, String[] pkgs) throws FormErrorException {
RESTAssert.assertNotEmpty(tname);
if ((pkgs == null) || (pkgs.length < 1)) {
throw this.createError("Please choose one or more packages!");
}
ETemplate template = this.dTemplate.findByName(tname);
RESTAssert.assertNotNull(template);
for (String pkg : pkgs) {
EPackage ep = this.dPkg.findByName(pkg);
List<EPackageVersion> pvs = new ArrayList<>(ep.getRPMs());
Collections.sort(pvs, new PackageVersionComparator());
template.getPackageVersions().add(pvs.get(pvs.size() - 1));
for (EService s : this.dSvc.findByPackage(ep)) {
EServiceDefaultState sds = this.dSvcDefState.findByName(s.getName(), template.getName());
if (sds == null) {
sds = new EServiceDefaultState();
sds.setService(s);
sds.setTemplate(template);
this.dSvcDefState.save(sds);
}
break;
}
}
this.dTemplate.save(template);// , "Added packages " + this.auditFormat(pkgs) + " to template " + tname);
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
@Override
@Transactional
public RenderedUI deleteTemplateView(String tname) {
RESTAssert.assertNotEmpty(tname);
ETemplate template = this.dTemplate.findByName(tname);
RESTAssert.assertNotNull(template);
CSViewModel modal = this.createModal("mDeleteTemplate");
modal.addModel("template", template);
return modal.render();
}
@Override
@Transactional
public AjaxAnswer deleteTemplate(String tname) throws FormErrorException {
RESTAssert.assertNotEmpty(tname);
ETemplate template = this.dTemplate.findByName(tname);
if ((template == null) || (template.getHosts().size() > 0)) {
throw this.createError("The template <b>" + tname + "</b> can't be removed. There are still hosts alive using this Template");
}
this.dTemplate.delete(template);
this.removeSidebarElement(tname);
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
@Override
@Transactional
public RenderedUI defaultServiceStatesView(String tname) {
ETemplate template = this.dTemplate.findByName(tname);
for (EService svc : this.dSvc.findList()) {
for (EPackageVersion pkv : template.getPackageVersions()) {
if (svc.getPackages().contains(pkv.getPkg())) {
this.setDefaultService(svc, template);
}
}
}
List<EServiceDefaultState> defaultStates = this.dSvcDefState.findByTemplate(template.getName());
Collections.sort(defaultStates, new DefaultStateComparator());
CSViewModel modal = this.createModal("mDefaultServices");
modal.addModel("template", template);
modal.addModel("defaultStates", defaultStates);
return modal.render();
}
private void setDefaultService(EService service, ETemplate template) {
EServiceDefaultState sds = this.dSvcDefState.findByName(service.getName(), template.getName());
if (sds == null) {
sds = new EServiceDefaultState();
sds.setService(service);
sds.setTemplate(template);
this.dSvcDefState.save(sds);
}
}
@Override
@Transactional
public AjaxAnswer changeDefaultServiceStates(String tname, List<String> startService, List<String> stopService) {
RESTAssert.assertNotEmpty(tname);
if (startService.isEmpty() && stopService.isEmpty()) {
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
List<EServiceDefaultState> services = this.dSvcDefState.findByTemplate(tname);
for (EServiceDefaultState eservice : services) {
if (startService.contains(eservice.getService().getName())) {
eservice.setState(ServiceState.STARTED);
this.dSvcDefState.save(eservice);
}
}
for (EServiceDefaultState eservice : services) {
if (stopService.contains(eservice.getService().getName())) {
eservice.setState(ServiceState.STOPPED);
this.dSvcDefState.save(eservice);
}
}
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
@Override
@Transactional
public RenderedUI addTemplateView() {
CSViewModel modal = this.createModal("mAddTemplate");
modal.addModel("availablePM", this.dPackageServer.findList());
return modal.render();
}
@Override
@Transactional
public AjaxAnswer addTemplate(String templatename, Long packageManagerId, String description, String autoupdate, String smoothupdate) throws FormErrorException {
this.templateOptionErrorHandling(templatename, packageManagerId, description, autoupdate, smoothupdate);
// save the new settings
ETemplate template = new ETemplate();
RESTAssert.assertNotNull(template);
template.setName(templatename);
template.setDescription(description);
template.setYum(this.dPackageServer.findById(packageManagerId));
template.setAutoUpdate(Boolean.valueOf(autoupdate));
template.setSmoothUpdate(Boolean.valueOf(smoothupdate));
this.dTemplate.save(template);
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
private void templateOptionErrorHandling(String templatename, Long packageManagerId, String description, String autoupdate, String smoothupdate) throws FormErrorException {
String errorMessage = "Please fill in all the information.";
FormErrorException error = null;
// templatename and packageManagerId are needed, description and auto update are not
error = this.checkForEmpty(templatename, errorMessage, error, "templatename");
error = this.checkForEmpty(packageManagerId.toString(), errorMessage, error, "packageManager");
if (packageManagerId < 0) {
if (error == null) {
error = this.createError(errorMessage);
}
error.addElementError("packageManager", true);
}
if (error != null) {
// add the currently entered values to the answer
error.addFormParam("templatename", templatename);
error.addFormParam("packageManager", packageManagerId.toString());
error.addFormParam("description", description);
error.addFormParam("autoupdate", autoupdate);
error.addFormParam("smoothupdate", smoothupdate);
throw error;
}
}
@Override
@Transactional
public RenderedUI editTemplateAgentConfigView(String tname) {
RESTAssert.assertNotEmpty(tname);
ETemplate template = this.dTemplate.findByName(tname);
RESTAssert.assertNotNull(template);
final CSViewModel vm = this.createModal("mTemplateAgentConfig");
vm.addModel("template", template);
EAgentOption options = this.dAgentOptions.findByTemplate(tname);
if (options == null) {
options = new EAgentOption();
options.setTemplate(template);
options = this.dAgentOptions.save(options);
}
vm.addModel("options", options);
vm.addModel("timeUnits", TimeUnit.values());
vm.addModel("taskStates", TaskState.values());
return vm.render();
}
@Override
@Transactional
public AjaxAnswer editTemplateAgentConfig(String tname, MultivaluedMap<String, String> form) throws FormErrorException {
RESTAssert.assertNotEmpty(tname);
ETemplate template = this.dTemplate.findByName(tname);
RESTAssert.assertNotNull(template);
FormValidator validator = FormValidator.create(this.getCurrentPath(), form);
validator.notEmpty("aliveTimer").notEmpty("aliveTimerUnit");
validator.notEmpty("doSshKeys").notEmpty("sshKeysTimer").notEmpty("sshKeysTimerUnit");
validator.notEmpty("doPackageManagement").notEmpty("packageManagementTimer").notEmpty("packageManagementTimerUnit");
validator.notEmpty("doFileManagement").notEmpty("fileManagementTimer").notEmpty("fileManagementTimerUnit");
validator.validate();
EAgentOption options = this.dAgentOptions.findByTemplate(tname);
if (options == null) {
options = new EAgentOption();
options.setTemplate(template);
}
options.setAliveTimer(Integer.valueOf(form.get("aliveTimer").get(0)));
options.setAliveTimerUnit(TimeUnit.valueOf(form.get("aliveTimerUnit").get(0)));
boolean resetSSH = (options.getDoSshKeys() == TaskState.ONCE) && (TaskState.valueOf(form.get("doSshKeys").get(0)) != TaskState.ONCE);
options.setDoSshKeys(TaskState.valueOf(form.get("doSshKeys").get(0)));
options.setSshKeysTimer(Integer.valueOf(form.get("sshKeysTimer").get(0)));
options.setSshKeysTimerUnit(TimeUnit.valueOf(form.get("sshKeysTimerUnit").get(0)));
boolean resetPkg = (options.getDoPackageManagement() == TaskState.ONCE) && (TaskState.valueOf(form.get("doPackageManagement").get(0)) != TaskState.ONCE);
options.setDoPackageManagement(TaskState.valueOf(form.get("doPackageManagement").get(0)));
options.setPackageManagementTimer(Integer.valueOf(form.get("packageManagementTimer").get(0)));
options.setPackageManagementTimerUnit(TimeUnit.valueOf(form.get("packageManagementTimerUnit").get(0)));
boolean resetFile = (options.getDoFileManagement() == TaskState.ONCE) && (TaskState.valueOf(form.get("doFileManagement").get(0)) != TaskState.ONCE);
options.setDoFileManagement(TaskState.valueOf(form.get("doFileManagement").get(0)));
options.setFileManagementTimer(Integer.valueOf(form.get("fileManagementTimer").get(0)));
options.setFileManagementTimerUnit(TimeUnit.valueOf(form.get("fileManagementTimerUnit").get(0)));
this.dAgentOptions.save(options);
if (resetSSH || resetPkg || resetFile) {
for (EHost host : this.dHosts.findList()) {
if (host.getTemplate().equals(template)) {
if (host.getExecutedPkg() && resetPkg) {
host.setExecutedPkg(false);
}
if (host.getExecutedSSH() && resetSSH) {
host.setExecutedSSH(false);
}
if (host.getExecutedFiles() && resetFile) {
host.setExecutedFiles(false);
}
this.dHosts.save(host);
}
}
}
return new AjaxAnswer(IWebPath.WEBROOT + ITemplate.ROOT);
}
}