Initial project's source code check-in.
This commit is contained in:
commit
b03b0b373f
4573 changed files with 981205 additions and 0 deletions
|
@ -0,0 +1,876 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.Net.Mail;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using WebsitePanel.Providers;
|
||||
using WebsitePanel.Providers.Web;
|
||||
using WebsitePanel.Providers.FTP;
|
||||
using WebsitePanel.Providers.Mail;
|
||||
using WebsitePanel.Providers.Database;
|
||||
using WebsitePanel.Providers.OS;
|
||||
using OS = WebsitePanel.Providers.OS;
|
||||
|
||||
|
||||
namespace WebsitePanel.EnterpriseServer
|
||||
{
|
||||
public class WebApplicationsInstaller
|
||||
{
|
||||
public const string PROPERTY_CONTENT_PATH = "installer.contentpath";
|
||||
public const string PROPERTY_ABSOLUTE_CONTENT_PATH = "installer.absolute.contentpath";
|
||||
public const string PROPERTY_VDIR_CREATED = "installer.virtualdircreated";
|
||||
public const string PROPERTY_DATABASE_CREATED = "installer.databasecreated";
|
||||
public const string PROPERTY_USER_CREATED = "installer.usercreated";
|
||||
public const string PROPERTY_INSTALLED_FILES = "installer.installedfiles";
|
||||
public const string PROPERTY_DELETE_FILES = "installer.deletefiles";
|
||||
public const string PROPERTY_DELETE_VDIR = "installer.deletevdir";
|
||||
public const string PROPERTY_DELETE_SQL = "installer.deletesql";
|
||||
public const string PROPERTY_DELETE_DATABASE = "installer.deletedatabase";
|
||||
public const string PROPERTY_DELETE_USER = "installer.deleteuser";
|
||||
|
||||
public static int InstallApplication(InstallationInfo inst)
|
||||
{
|
||||
// check account
|
||||
int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo | DemandAccount.IsActive);
|
||||
if (accountCheck < 0) return accountCheck;
|
||||
|
||||
// check package
|
||||
int packageCheck = SecurityContext.CheckPackage(inst.PackageId, DemandPackage.IsActive);
|
||||
if (packageCheck < 0) return packageCheck;
|
||||
|
||||
// install application
|
||||
WebApplicationsInstaller installer = new WebApplicationsInstaller();
|
||||
return installer.InstallWebApplication(inst);
|
||||
}
|
||||
|
||||
ApplicationInfo app = null;
|
||||
private string contentPath = null;
|
||||
private string siteId = null;
|
||||
private OS.OperatingSystem os = null;
|
||||
private DatabaseServer sql = null;
|
||||
private string serverIpAddressExternal = null;
|
||||
private string serverIpAddressInternal = null;
|
||||
private string webSiteName = "";
|
||||
|
||||
public int InstallWebApplication(InstallationInfo inst)
|
||||
{
|
||||
// place log record
|
||||
TaskManager.StartTask("APP_INSTALLER", "INSTALL_APPLICATION");
|
||||
TaskManager.WriteParameter("Virtual directory", inst.VirtualDir);
|
||||
TaskManager.WriteParameter("Database group", inst.DatabaseGroup);
|
||||
TaskManager.ItemId = inst.PackageId;
|
||||
|
||||
try
|
||||
{
|
||||
// get application info
|
||||
app = GetApplication(inst.PackageId, inst.ApplicationId);
|
||||
|
||||
TaskManager.ItemName = app.Name;
|
||||
|
||||
// check web site for existance
|
||||
WebSite webSite = WebServerController.GetWebSite(inst.WebSiteId);
|
||||
|
||||
if (webSite == null)
|
||||
return BusinessErrorCodes.ERROR_WEB_INSTALLER_WEBSITE_NOT_EXISTS;
|
||||
|
||||
TaskManager.WriteParameter("Web site", webSite.Name);
|
||||
|
||||
webSiteName = webSite.Name;
|
||||
siteId = webSite.SiteId;
|
||||
|
||||
// change web site properties if required
|
||||
if (String.IsNullOrEmpty(inst.VirtualDir))
|
||||
{
|
||||
ChangeVirtualDirectoryProperties(webSite, app.WebSettings);
|
||||
WebServerController.UpdateWebSite(webSite);
|
||||
}
|
||||
|
||||
// get OS service
|
||||
int osId = PackageController.GetPackageServiceId(inst.PackageId, "os");
|
||||
os = new OS.OperatingSystem();
|
||||
ServiceProviderProxy.Init(os, osId);
|
||||
|
||||
// get remote content path
|
||||
contentPath = webSite.ContentPath;
|
||||
|
||||
// create virtual dir if required
|
||||
if (!String.IsNullOrEmpty(inst.VirtualDir))
|
||||
{
|
||||
// check if the required virtual dir already exists
|
||||
contentPath = Path.Combine(contentPath, inst.VirtualDir);
|
||||
|
||||
WebVirtualDirectory vdir = null;
|
||||
int result = WebServerController.AddVirtualDirectory(inst.WebSiteId, inst.VirtualDir, contentPath);
|
||||
if (result == BusinessErrorCodes.ERROR_VDIR_ALREADY_EXISTS)
|
||||
{
|
||||
// the directory alredy exists
|
||||
vdir = WebServerController.GetVirtualDirectory(
|
||||
inst.WebSiteId, inst.VirtualDir);
|
||||
|
||||
contentPath = vdir.ContentPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
vdir = WebServerController.GetVirtualDirectory(
|
||||
inst.WebSiteId, inst.VirtualDir);
|
||||
|
||||
inst[PROPERTY_VDIR_CREATED] = "True";
|
||||
}
|
||||
|
||||
// change virtual directory properties if required
|
||||
ChangeVirtualDirectoryProperties(vdir, app.WebSettings);
|
||||
WebServerController.UpdateVirtualDirectory(inst.WebSiteId, vdir);
|
||||
}
|
||||
|
||||
// deploy application codebase ZIP and then unpack it
|
||||
string codebasePath = app.Codebase;
|
||||
string remoteCodebasePath = Path.Combine(contentPath, Path.GetFileName(app.Codebase));
|
||||
|
||||
// make content path absolute
|
||||
string absContentPath = FilesController.GetFullPackagePath(inst.PackageId, contentPath);
|
||||
|
||||
// save content path
|
||||
inst[PROPERTY_CONTENT_PATH] = contentPath;
|
||||
inst[PROPERTY_ABSOLUTE_CONTENT_PATH] = absContentPath;
|
||||
|
||||
// copy ZIP to the target server
|
||||
FileStream stream = File.OpenRead(codebasePath);
|
||||
int BUFFER_LENGTH = 5000000;
|
||||
|
||||
byte[] buffer = new byte[BUFFER_LENGTH];
|
||||
int readBytes = 0;
|
||||
while (true)
|
||||
{
|
||||
readBytes = stream.Read(buffer, 0, BUFFER_LENGTH);
|
||||
|
||||
if (readBytes < BUFFER_LENGTH)
|
||||
Array.Resize<byte>(ref buffer, readBytes);
|
||||
|
||||
FilesController.AppendFileBinaryChunk(inst.PackageId, remoteCodebasePath, buffer);
|
||||
|
||||
if (readBytes < BUFFER_LENGTH)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// unpack codebase
|
||||
inst[PROPERTY_INSTALLED_FILES] = String.Join(";",
|
||||
FilesController.UnzipFiles(inst.PackageId, new string[] { remoteCodebasePath }));
|
||||
|
||||
// delete codebase zip
|
||||
FilesController.DeleteFiles(inst.PackageId, new string[] { remoteCodebasePath });
|
||||
|
||||
// check/create databases
|
||||
if (!String.IsNullOrEmpty(inst.DatabaseGroup) &&
|
||||
String.Compare(inst.DatabaseGroup, "None", true) != 0)
|
||||
{
|
||||
// database
|
||||
if (inst.DatabaseId == 0)
|
||||
{
|
||||
TaskManager.WriteParameter("Database name", inst.DatabaseName);
|
||||
|
||||
// we should create a new database
|
||||
SqlDatabase db = new SqlDatabase();
|
||||
db.PackageId = inst.PackageId;
|
||||
db.Name = inst.DatabaseName;
|
||||
inst.DatabaseId = DatabaseServerController.AddSqlDatabase(db, inst.DatabaseGroup);
|
||||
if (inst.DatabaseId < 0)
|
||||
{
|
||||
// rollback installation
|
||||
RollbackInstallation(inst);
|
||||
|
||||
// return error
|
||||
return inst.DatabaseId; // there was an error when creating database
|
||||
}
|
||||
|
||||
inst[PROPERTY_DATABASE_CREATED] = "True";
|
||||
}
|
||||
else
|
||||
{
|
||||
// existing database
|
||||
SqlDatabase db = DatabaseServerController.GetSqlDatabase(inst.DatabaseId);
|
||||
inst.DatabaseName = db.Name;
|
||||
|
||||
TaskManager.WriteParameter("Database name", inst.DatabaseName);
|
||||
}
|
||||
|
||||
SqlUser user = null;
|
||||
// database user
|
||||
if (inst.UserId == 0)
|
||||
{
|
||||
TaskManager.WriteParameter("Database user", inst.Username);
|
||||
|
||||
// NEW USER
|
||||
user = new SqlUser();
|
||||
user.PackageId = inst.PackageId;
|
||||
user.Name = inst.Username;
|
||||
user.Databases = new string[] { inst.DatabaseName };
|
||||
user.Password = inst.Password;
|
||||
inst.UserId = DatabaseServerController.AddSqlUser(user, inst.DatabaseGroup);
|
||||
if (inst.UserId < 0)
|
||||
{
|
||||
// rollback installation
|
||||
RollbackInstallation(inst);
|
||||
|
||||
// return error
|
||||
return inst.UserId; // error while adding user
|
||||
}
|
||||
|
||||
inst[PROPERTY_USER_CREATED] = "True";
|
||||
}
|
||||
else
|
||||
{
|
||||
// EXISTING USER
|
||||
user = DatabaseServerController.GetSqlUser(inst.UserId);
|
||||
inst.Username = user.Name;
|
||||
|
||||
TaskManager.WriteParameter("Database user", inst.Username);
|
||||
|
||||
List<string> databases = new List<string>();
|
||||
databases.AddRange(user.Databases);
|
||||
|
||||
if (!databases.Contains(inst.DatabaseName))
|
||||
{
|
||||
databases.Add(inst.DatabaseName);
|
||||
|
||||
user.Databases = databases.ToArray();
|
||||
DatabaseServerController.UpdateSqlUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
// check connectivity with SQL Server and credentials provided
|
||||
// load user item
|
||||
int sqlServiceId = PackageController.GetPackageServiceId(inst.PackageId, inst.DatabaseGroup);
|
||||
sql = new DatabaseServer();
|
||||
ServiceProviderProxy.Init(sql, sqlServiceId);
|
||||
|
||||
if (!sql.CheckConnectivity(inst.DatabaseName, inst.Username,
|
||||
inst.Password))
|
||||
{
|
||||
// can't connect to the database
|
||||
RollbackInstallation(inst);
|
||||
|
||||
return BusinessErrorCodes.ERROR_WEB_INSTALLER_CANT_CONNECT_DATABASE;
|
||||
}
|
||||
|
||||
// read SQL server settings
|
||||
StringDictionary settings = ServerController.GetServiceSettings(sqlServiceId);
|
||||
serverIpAddressExternal = settings["ExternalAddress"];
|
||||
if (settings.ContainsKey("InternalAddress"))
|
||||
{
|
||||
serverIpAddressInternal = settings["InternalAddress"];
|
||||
}
|
||||
}
|
||||
|
||||
// ********* RUN INSTALL SCENARIO ***********
|
||||
int scriptResult = RunInstallScenario(inst);
|
||||
if (scriptResult < 0)
|
||||
{
|
||||
// rollback installation
|
||||
RollbackInstallation(inst);
|
||||
|
||||
// return error
|
||||
return scriptResult;
|
||||
}
|
||||
|
||||
// add new installation to the database
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// rollback installation
|
||||
RollbackInstallation(inst);
|
||||
|
||||
throw TaskManager.WriteError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TaskManager.CompleteTask();
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeVirtualDirectoryProperties(WebVirtualDirectory vdir,
|
||||
ApplicationWebSetting[] settings)
|
||||
{
|
||||
if (settings == null)
|
||||
return;
|
||||
|
||||
// get type properties
|
||||
Type vdirType = vdir.GetType();
|
||||
foreach (ApplicationWebSetting setting in settings)
|
||||
{
|
||||
PropertyInfo prop = vdirType.GetProperty(setting.Name,
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (prop != null)
|
||||
{
|
||||
prop.SetValue(vdir, ObjectUtils.Cast(setting.Value, prop.PropertyType), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int RunInstallScenario(InstallationInfo inst)
|
||||
{
|
||||
string scenarioPath = Path.Combine(app.Folder, "Install.xml");
|
||||
return RunScenario(scenarioPath, inst, true);
|
||||
}
|
||||
|
||||
private string GetFullPathToInstallFolder(int userId)
|
||||
{
|
||||
string userhomeFolder = String.Empty;
|
||||
string[] osSesstings = os.ServiceProviderSettingsSoapHeaderValue.Settings;
|
||||
foreach (string s in osSesstings)
|
||||
{
|
||||
if (s.Contains("usershome"))
|
||||
{
|
||||
string[] split = s.Split(new char[] {'='});
|
||||
userhomeFolder = split[1];
|
||||
}
|
||||
}
|
||||
UserInfo info = UserController.GetUser(userId);
|
||||
return Path.Combine(userhomeFolder, info.Username);
|
||||
}
|
||||
|
||||
private int RunScenario(string scenarioPath, InstallationInfo inst, bool throwExceptions)
|
||||
{
|
||||
// load XML document
|
||||
XmlDocument docScenario = new XmlDocument();
|
||||
docScenario.Load(scenarioPath);
|
||||
|
||||
// go through "check" section
|
||||
XmlNode nodeCheck = docScenario.SelectSingleNode("//check");
|
||||
if (nodeCheck != null)
|
||||
{
|
||||
foreach (XmlNode nodeStep in nodeCheck.ChildNodes)
|
||||
{
|
||||
if (nodeStep.Name == "fileExists")
|
||||
{
|
||||
/*
|
||||
// check if the specified file exists
|
||||
string fileName = nodeStep.Attributes["path"].Value;
|
||||
fileName = ExpandVariables(fileName, inst);
|
||||
if (fileName.StartsWith("\\"))
|
||||
{
|
||||
fileName = fileName.Substring(1);
|
||||
}
|
||||
//get full path to instal folder
|
||||
PackageInfo package = PackageController.GetPackage(inst.PackageId);
|
||||
string fullPath = Path.Combine(GetFullPathToInstallFolder(package.UserId), fileName);
|
||||
if (os.FileExists(fullPath))
|
||||
return BusinessErrorCodes.ERROR_WEB_INSTALLER_TARGET_WEBSITE_UNSUITABLE;
|
||||
*/
|
||||
}
|
||||
else if (nodeStep.Name == "sql")
|
||||
{
|
||||
string cmdText = nodeStep.InnerText;
|
||||
cmdText = ExpandVariables(cmdText, inst);
|
||||
|
||||
DataSet dsResults = sql.ExecuteSqlQuery(inst.DatabaseName, cmdText);
|
||||
if (dsResults.Tables[0].Rows.Count > 0)
|
||||
return BusinessErrorCodes.ERROR_WEB_INSTALLER_TARGET_DATABASE_UNSUITABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// go through "commands" section
|
||||
XmlNode nodeCommands = docScenario.SelectSingleNode("//commands");
|
||||
if (nodeCommands != null)
|
||||
{
|
||||
foreach (XmlNode nodeCommand in nodeCommands.ChildNodes)
|
||||
{
|
||||
if (nodeCommand.Name == "processFile")
|
||||
{
|
||||
// process remote file
|
||||
string fileName = nodeCommand.Attributes["path"].Value;
|
||||
fileName = ExpandVariables(fileName, inst);
|
||||
|
||||
byte[] fileBinaryContent = FilesController.GetFileBinaryContent(inst.PackageId, fileName);
|
||||
if (fileBinaryContent == null)
|
||||
throw new Exception("Could not process scenario file: " + fileName);
|
||||
|
||||
string fileContent = Encoding.UTF8.GetString(fileBinaryContent);
|
||||
fileContent = ExpandVariables(fileContent, inst);
|
||||
|
||||
FilesController.UpdateFileBinaryContent(inst.PackageId, fileName,
|
||||
Encoding.UTF8.GetBytes(fileContent));
|
||||
}
|
||||
else if (nodeCommand.Name == "runSql")
|
||||
{
|
||||
string cmdText = nodeCommand.InnerText;
|
||||
if (nodeCommand.Attributes["path"] != null)
|
||||
{
|
||||
// load SQL from file
|
||||
string sqlPath = Path.Combine(app.Folder, nodeCommand.Attributes["path"].Value);
|
||||
|
||||
if (!File.Exists(sqlPath))
|
||||
continue;
|
||||
|
||||
StreamReader reader = new StreamReader(sqlPath);
|
||||
cmdText = reader.ReadToEnd();
|
||||
reader.Close();
|
||||
}
|
||||
|
||||
bool run = true;
|
||||
if (nodeCommand.Attributes["dependsOnProperty"] != null)
|
||||
{
|
||||
string[] propNames = nodeCommand.Attributes["dependsOnProperty"].Value.Split(',');
|
||||
foreach (string propName in propNames)
|
||||
{
|
||||
if (inst[propName.Trim()] == null)
|
||||
{
|
||||
run = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (run)
|
||||
{
|
||||
try
|
||||
{
|
||||
cmdText = ExpandVariables(cmdText, inst);
|
||||
sql.ExecuteSqlNonQuerySafe(inst.DatabaseName, inst.Username, inst.Password, cmdText);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwExceptions)
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
string appUrls = null;
|
||||
private string ExpandVariables(string str, InstallationInfo inst)
|
||||
{
|
||||
str = ReplaceTemplateVariable(str, "installer.contentpath", inst[PROPERTY_CONTENT_PATH]);
|
||||
str = ReplaceTemplateVariable(str, "installer.website", webSiteName);
|
||||
str = ReplaceTemplateVariable(str, "installer.virtualdir", inst.VirtualDir);
|
||||
|
||||
string fullWebPath = webSiteName;
|
||||
if (!String.IsNullOrEmpty(inst.VirtualDir))
|
||||
fullWebPath += "/" + inst.VirtualDir;
|
||||
|
||||
// try to load domain info
|
||||
DomainInfo domain = ServerController.GetDomain(webSiteName);
|
||||
string fullWebPathPrefix = (domain != null && domain.IsSubDomain) ? "" : "www.";
|
||||
|
||||
// app URLs
|
||||
if (appUrls == null)
|
||||
{
|
||||
// read web pointers
|
||||
List<DomainInfo> sitePointers = WebServerController.GetWebSitePointers(inst.WebSiteId);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("<urls>");
|
||||
sb.Append("<url value=\"").Append(fullWebPath).Append("\"/>");
|
||||
foreach (DomainInfo pointer in sitePointers)
|
||||
{
|
||||
string pointerWebPath = pointer.DomainName;
|
||||
if (!String.IsNullOrEmpty(inst.VirtualDir))
|
||||
pointerWebPath += "/" + inst.VirtualDir;
|
||||
sb.Append("<url value=\"").Append(pointerWebPath).Append("\"/>");
|
||||
}
|
||||
sb.Append("</urls>");
|
||||
appUrls = sb.ToString();
|
||||
}
|
||||
str = ReplaceTemplateVariable(str, "installer.appurls", appUrls);
|
||||
|
||||
string slashVirtualDir = "";
|
||||
if (!String.IsNullOrEmpty(inst.VirtualDir))
|
||||
slashVirtualDir = "/" + inst.VirtualDir;
|
||||
|
||||
str = ReplaceTemplateVariable(str, "installer.slashvirtualdir", slashVirtualDir);
|
||||
str = ReplaceTemplateVariable(str, "installer.website.www", fullWebPathPrefix + webSiteName);
|
||||
str = ReplaceTemplateVariable(str, "installer.fullwebpath", fullWebPath);
|
||||
str = ReplaceTemplateVariable(str, "installer.fullwebpath.www", fullWebPathPrefix + fullWebPath);
|
||||
//Replace ObjectQualifierNormalized which is not defined on portal
|
||||
str = ReplaceTemplateVariable(str, "ObjectQualifierNormalized", "");
|
||||
|
||||
/*
|
||||
* Application installer variable 'installer.database.server' is obsolete
|
||||
* and should not be used to install Application Packs.
|
||||
* Instead, please use the following two variables:
|
||||
* - installer.database.server.external - defines external database address
|
||||
* - installer.database.server.internal - defines internal database address
|
||||
*
|
||||
* See TFS Issue 952 for details.
|
||||
*/
|
||||
//apply external database address
|
||||
str = ReplaceTemplateVariable(str, "installer.database.server",
|
||||
((serverIpAddressExternal != null) ? serverIpAddressExternal : ""));
|
||||
str = ReplaceTemplateVariable(str, "installer.database.server.external",
|
||||
((serverIpAddressExternal != null) ? serverIpAddressExternal : String.Empty));
|
||||
|
||||
//apply internal database address
|
||||
str = ReplaceTemplateVariable(str, "installer.database.server.internal",
|
||||
((serverIpAddressInternal != null) ? serverIpAddressInternal : String.Empty));
|
||||
|
||||
str = ReplaceTemplateVariable(str, "installer.database", inst.DatabaseName);
|
||||
str = ReplaceTemplateVariable(str, "installer.database.user", inst.Username);
|
||||
str = ReplaceTemplateVariable(str, "installer.database.password",
|
||||
((inst.Password != null) ? inst.Password : ""));
|
||||
foreach (string[] pair in inst.PropertiesArray)
|
||||
str = ReplaceTemplateVariable(str, pair[0], pair[1]);
|
||||
return str;
|
||||
}
|
||||
|
||||
private string ReplaceTemplateVariable(string str, string varName, string varValue)
|
||||
{
|
||||
if (String.IsNullOrEmpty(str) || String.IsNullOrEmpty(varName))
|
||||
return str;
|
||||
|
||||
str = Regex.Replace(str, "\\$\\{" + varName + "\\}+", varValue, RegexOptions.IgnoreCase);
|
||||
str = Regex.Replace(str, "\\$\\{" + varName + ".mysql-escaped\\}+", EscapeMySql(varValue), RegexOptions.IgnoreCase);
|
||||
return Regex.Replace(str, "\\$\\{" + varName + ".mssql-escaped\\}+", EscapeMsSql(varValue), RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
private string EscapeMySql(string str)
|
||||
{
|
||||
if (String.IsNullOrEmpty(str))
|
||||
return str;
|
||||
|
||||
return str.Replace("'", "\\'")
|
||||
.Replace("\"", "\\\"")
|
||||
.Replace("\n", "\\n")
|
||||
.Replace("\r", "\\r")
|
||||
.Replace("\t", "\\t")
|
||||
.Replace("\\", "\\\\")
|
||||
.Replace("\0", "\\0");
|
||||
}
|
||||
|
||||
private string EscapeMsSql(string str)
|
||||
{
|
||||
if (String.IsNullOrEmpty(str))
|
||||
return str;
|
||||
|
||||
return str.Replace("'", "''");
|
||||
}
|
||||
|
||||
private void RollbackInstallation(InstallationInfo inst)
|
||||
{
|
||||
// remove virtual dir
|
||||
if (inst[PROPERTY_VDIR_CREATED] != null)
|
||||
{
|
||||
// delete virtual directory
|
||||
WebServerController.DeleteVirtualDirectory(inst.WebSiteId, inst.VirtualDir);
|
||||
|
||||
// delete folder
|
||||
FilesController.DeleteFiles(inst.PackageId, new string[] { inst[PROPERTY_CONTENT_PATH] });
|
||||
}
|
||||
|
||||
// remove database
|
||||
if (inst[PROPERTY_DATABASE_CREATED] != null)
|
||||
DatabaseServerController.DeleteSqlDatabase(inst.DatabaseId);
|
||||
|
||||
// remove database user
|
||||
if (inst[PROPERTY_USER_CREATED] != null)
|
||||
DatabaseServerController.DeleteSqlUser(inst.UserId);
|
||||
}
|
||||
|
||||
public static List<ApplicationCategory> GetCategories()
|
||||
{
|
||||
List<ApplicationCategory> categories = null;
|
||||
|
||||
string key = "WebApplicationCategories";
|
||||
|
||||
// look up in the cache
|
||||
if (HttpContext.Current != null)
|
||||
categories = (List<ApplicationCategory>)HttpContext.Current.Cache[key];
|
||||
|
||||
if (categories == null)
|
||||
{
|
||||
string catsPath = Path.Combine(ConfigSettings.WebApplicationsPath, "Applications.xml");
|
||||
if (File.Exists(catsPath))
|
||||
{
|
||||
categories = new List<ApplicationCategory>();
|
||||
|
||||
// parse file
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(catsPath);
|
||||
|
||||
XmlNodeList nodesCategories = doc.SelectNodes("categories/category");
|
||||
foreach (XmlNode nodeCategory in nodesCategories)
|
||||
{
|
||||
ApplicationCategory category = new ApplicationCategory();
|
||||
category.Id = nodeCategory.Attributes["id"].Value;
|
||||
category.Name = GetNodeValue(nodeCategory, "name", category.Id);
|
||||
categories.Add(category);
|
||||
|
||||
// read applications
|
||||
List<string> catApps = new List<string>();
|
||||
XmlNodeList nodesApps = nodeCategory.SelectNodes("applications/application");
|
||||
foreach (XmlNode nodeApp in nodesApps)
|
||||
catApps.Add(nodeApp.Attributes["name"].Value);
|
||||
category.Applications = catApps.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
// place to the cache
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Cache.Insert(key, categories, new CacheDependency(catsPath));
|
||||
}
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
public static List<ApplicationInfo> GetApplications(int packageId)
|
||||
{
|
||||
return GetApplications(packageId, null);
|
||||
}
|
||||
|
||||
public static List<ApplicationInfo> GetApplications(int packageId, string categoryId)
|
||||
{
|
||||
string key = "WebApplicationsList";
|
||||
|
||||
Dictionary<string, ApplicationInfo> apps = null;
|
||||
|
||||
// look up in the cache
|
||||
if(HttpContext.Current != null)
|
||||
apps = (Dictionary<string, ApplicationInfo>)HttpContext.Current.Cache[key];
|
||||
|
||||
if (apps == null)
|
||||
{
|
||||
// create apps list
|
||||
apps = new Dictionary<string, ApplicationInfo>();
|
||||
|
||||
string appsRoot = ConfigSettings.WebApplicationsPath;
|
||||
string[] dirs = Directory.GetDirectories(appsRoot);
|
||||
foreach (string dir in dirs)
|
||||
{
|
||||
string appFile = Path.Combine(dir, "Application.xml");
|
||||
|
||||
if (!File.Exists(appFile))
|
||||
continue;
|
||||
|
||||
// read and parse web applications xml file
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(appFile);
|
||||
|
||||
XmlNode nodeApp = doc.SelectSingleNode("//application");
|
||||
|
||||
string appFolder = dir;
|
||||
|
||||
// parse node
|
||||
ApplicationInfo app = CreateApplicationInfoFromXml(appFolder, nodeApp);
|
||||
|
||||
// add to the collection
|
||||
apps.Add(app.Id, app);
|
||||
}
|
||||
|
||||
// place to the cache
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Cache.Insert(key, apps, new CacheDependency(appsRoot));
|
||||
}
|
||||
|
||||
// filter applications based on category
|
||||
List<ApplicationInfo> categoryApps = new List<ApplicationInfo>();
|
||||
|
||||
// check if the application fits requirements
|
||||
PackageContext cntx = PackageController.GetPackageContext(packageId);
|
||||
|
||||
List<ApplicationCategory> categories = GetCategories();
|
||||
foreach (ApplicationCategory category in categories)
|
||||
{
|
||||
// skip category if required
|
||||
if (!String.IsNullOrEmpty(categoryId)
|
||||
&& String.Compare(category.Id, categoryId, true) != 0)
|
||||
continue;
|
||||
|
||||
// iterate through applications
|
||||
foreach (string appId in category.Applications)
|
||||
{
|
||||
if (apps.ContainsKey(appId)
|
||||
&& IsApplicattionFitsRequirements(cntx, apps[appId]))
|
||||
categoryApps.Add(apps[appId]);
|
||||
}
|
||||
}
|
||||
|
||||
return categoryApps;
|
||||
}
|
||||
|
||||
public static ApplicationInfo GetApplication(int packageId, string applicationId)
|
||||
{
|
||||
// get all applications
|
||||
List<ApplicationInfo> apps = GetApplications(packageId);
|
||||
|
||||
// check if the application fits requirements
|
||||
PackageContext cntx = PackageController.GetPackageContext(packageId);
|
||||
|
||||
// find the application
|
||||
foreach (ApplicationInfo app in apps)
|
||||
{
|
||||
if (app.Id.ToLower() == applicationId.ToLower())
|
||||
{
|
||||
return IsApplicattionFitsRequirements(cntx, app) ? app : null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool IsApplicattionFitsRequirements(PackageContext cntx, ApplicationInfo app)
|
||||
{
|
||||
if (app.Requirements == null)
|
||||
return true; // empty requirements
|
||||
|
||||
foreach (ApplicationRequirement req in app.Requirements)
|
||||
{
|
||||
// check if this is a group
|
||||
if (req.Groups != null)
|
||||
{
|
||||
bool groupFits = false;
|
||||
foreach (string group in req.Groups)
|
||||
{
|
||||
if (cntx.Groups.ContainsKey(group))
|
||||
{
|
||||
groupFits = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!groupFits)
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if this is a quota
|
||||
if (req.Quotas != null)
|
||||
{
|
||||
bool quotaFits = false;
|
||||
foreach (string quota in req.Quotas)
|
||||
{
|
||||
if (cntx.Quotas.ContainsKey(quota) &&
|
||||
!cntx.Quotas[quota].QuotaExhausted)
|
||||
{
|
||||
quotaFits = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!quotaFits)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region private helper methods
|
||||
private static ApplicationInfo CreateApplicationInfoFromXml(string appFolder, XmlNode nodeApp)
|
||||
{
|
||||
ApplicationInfo app = new ApplicationInfo();
|
||||
|
||||
// category name
|
||||
app.CategoryName = GetNodeValue(nodeApp, "category", "");
|
||||
|
||||
// attributes
|
||||
app.Id = nodeApp.Attributes["id"].Value;
|
||||
app.Codebase = nodeApp.Attributes["codebase"].Value;
|
||||
app.SettingsControl = nodeApp.Attributes["settingsControl"].Value;
|
||||
app.Folder = appFolder;
|
||||
|
||||
// child nodes
|
||||
app.Name = GetNodeValue(nodeApp, "name", "");
|
||||
app.ShortDescription = GetNodeValue(nodeApp, "shortDescription", "");
|
||||
app.FullDescription = GetNodeValue(nodeApp, "fullDescription", "");
|
||||
app.Logo = GetNodeValue(nodeApp, "logo", "");
|
||||
app.Version = GetNodeValue(nodeApp, "version", "");
|
||||
app.Size = Int32.Parse(GetNodeValue(nodeApp, "size", "0"));
|
||||
app.HomeSite = GetNodeValue(nodeApp, "homeSite", "");
|
||||
app.SupportSite = GetNodeValue(nodeApp, "supportSite", "");
|
||||
app.DocsSite = GetNodeValue(nodeApp, "docSite", "");
|
||||
|
||||
app.Manufacturer = GetNodeValue(nodeApp, "manufacturer", "");
|
||||
app.License = GetNodeValue(nodeApp, "license", "");
|
||||
|
||||
// process codebase path
|
||||
app.Codebase = Path.Combine(appFolder, app.Codebase);
|
||||
|
||||
// web settings
|
||||
List<ApplicationWebSetting> settings = new List<ApplicationWebSetting>();
|
||||
XmlNodeList nodesWebSettings = nodeApp.SelectNodes("webSettings/add");
|
||||
foreach (XmlNode nodeSetting in nodesWebSettings)
|
||||
{
|
||||
ApplicationWebSetting setting = new ApplicationWebSetting();
|
||||
setting.Name = nodeSetting.Attributes["name"].Value;
|
||||
setting.Value = nodeSetting.Attributes["value"].Value;
|
||||
settings.Add(setting);
|
||||
}
|
||||
app.WebSettings = settings.ToArray();
|
||||
|
||||
// requirements
|
||||
List<ApplicationRequirement> requirements = new List<ApplicationRequirement>();
|
||||
XmlNodeList nodesRequirements = nodeApp.SelectNodes("requirements/add");
|
||||
foreach (XmlNode nodesRequirement in nodesRequirements)
|
||||
{
|
||||
ApplicationRequirement req = new ApplicationRequirement();
|
||||
|
||||
if (nodesRequirement.Attributes["group"] != null)
|
||||
req.Groups = nodesRequirement.Attributes["group"].Value.Split('|');
|
||||
|
||||
if (nodesRequirement.Attributes["quota"] != null)
|
||||
req.Quotas = nodesRequirement.Attributes["quota"].Value.Split('|');
|
||||
|
||||
req.Display = true;
|
||||
if (nodesRequirement.Attributes["display"] != null)
|
||||
req.Display = Utils.ParseBool(nodesRequirement.Attributes["display"].Value, true);
|
||||
|
||||
requirements.Add(req);
|
||||
}
|
||||
app.Requirements = requirements.ToArray();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
private static string GetNodeValue(XmlNode parentNode, string nodeName, string defaultValue)
|
||||
{
|
||||
XmlNode node = parentNode.SelectSingleNode(nodeName);
|
||||
if (node != null)
|
||||
{
|
||||
return node.InnerText.Trim();
|
||||
}
|
||||
|
||||
// return default value
|
||||
return defaultValue;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue