From f7d7bcfafc5d9210653a7c9774036c9e1c5dd22e Mon Sep 17 00:00:00 2001 From: Haya Nmeir Date: Sun, 16 Sep 2012 02:22:05 +0300 Subject: [PATCH] This built contains the functionality to set hard quota on the website content folder. It requires FSRM to be installed on the File Server, Name of the share where the home folders are create should contain the drive name preceeded by _ e.g. SharedConfig_C. Quota is retrieved from OS disk space quota, quota unit is retrieved from quota description field in the quotas table, this info is fed to Dirquota command and the quota is set accordingly. --- .../Code/Files/FilesController.cs | 71 +++++++++++ .../Code/WebServers/WebServerController.cs | 3 + .../WebsitePanel.EnterpriseServer/Web.config | 40 +++--- .../WebsitePanel.EnterpriseServer.csproj | 6 + .../OS/IOperatingSystem.cs | 1 + .../WebsitePanel.Providers.Base.csproj | 9 ++ .../Windows2003.cs | 11 ++ .../OperatingSystemProxy.cs | 87 ++++++++++++- .../WebsitePanel.Server.Utils/FileUtils.cs | 116 ++++++++++++++++++ .../OperatingSystem.asmx.cs | 17 +++ .../Sources/WebsitePanel.Server/Web.config | 2 +- .../WebsitePanel.Server.csproj | 5 + .../WebsitePanel.WebPortal.csproj | 1 + 13 files changed, 347 insertions(+), 22 deletions(-) diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Files/FilesController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Files/FilesController.cs index 7784cad8..4314bcd0 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Files/FilesController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Files/FilesController.cs @@ -912,5 +912,76 @@ namespace WebsitePanel.EnterpriseServer return users.ToArray(); } + + public static int SetFolderQuota(int packageId, string path) + { + + // check account + int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo | DemandAccount.IsActive); + if (accountCheck < 0) return accountCheck; + + // check package + int packageCheck = SecurityContext.CheckPackage(packageId, DemandPackage.IsActive); + if (packageCheck < 0) return packageCheck; + + // place log record + TaskManager.StartTask("FILES", "SET_QUOTA_ON_FOLDER", path); + TaskManager.ItemId = packageId; + + try + { + + // file server cluster name + string fileServerClusterName = String.Empty; + + // Share Name where home folders are created + string shareName = String.Empty; + + string[] splits = GetHomeFolder(packageId).Split('\\'); + + if (splits.Length > 4) + { + fileServerClusterName = splits[2]; + shareName = splits[3]; + } + + // disk space quota + QuotaValueInfo diskSpaceQuota = PackageController.GetPackageQuota(packageId, Quotas.OS_DISKSPACE); + + // bat file pat + string cmdFilePath = @"\\" + fileServerClusterName + @"\" + shareName + @"\" + "Process.bat"; + + #region figure Quota Unit + + // Quota Unit + string unit = String.Empty; + if (diskSpaceQuota.QuotaDescription.ToLower().Contains("gb")) + unit = "GB"; + else if (diskSpaceQuota.QuotaDescription.ToLower().Contains("mb")) + unit = "MB"; + else + unit = "KB"; + + #endregion + + OS.OperatingSystem os = GetOS(packageId); + os.SetQuotaLimitOnFolder(cmdFilePath, fileServerClusterName, path, diskSpaceQuota.QuotaAllocatedValue.ToString() + unit, 0, String.Empty, String.Empty); + + return 0; + } + catch (Exception ex) + { + //Log and return a generic error rather than throwing an exception + TaskManager.WriteError(ex); + return BusinessErrorCodes.ERROR_FILE_GENERIC_LOGGED; + } + finally + { + TaskManager.CompleteTask(); + } + + + } + } } diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/WebServers/WebServerController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/WebServers/WebServerController.cs index 5ea67ab0..a703fa4f 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/WebServers/WebServerController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/WebServers/WebServerController.cs @@ -377,6 +377,9 @@ namespace WebsitePanel.EnterpriseServer // CREATE WEB SITE siteId = web.CreateSite(site); + // Set hard quota on the website content folder + FilesController.SetFolderQuota(packageId, site.DataPath); + // register item site.ServiceId = serviceId; site.PackageId = packageId; diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Web.config b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Web.config index b78330c8..56350e5d 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Web.config +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Web.config @@ -1,56 +1,56 @@ - + -
+
- + - + - + - + - + - + - + - + - - - + + + - + - + - + - - + + - + - + \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/WebsitePanel.EnterpriseServer.csproj b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/WebsitePanel.EnterpriseServer.csproj index 52285130..ac8ea558 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/WebsitePanel.EnterpriseServer.csproj +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/WebsitePanel.EnterpriseServer.csproj @@ -19,6 +19,11 @@ v4.0 + false + + + + true @@ -410,6 +415,7 @@ + diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/OS/IOperatingSystem.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/OS/IOperatingSystem.cs index fc9f3076..73088563 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/OS/IOperatingSystem.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/OS/IOperatingSystem.cs @@ -81,5 +81,6 @@ namespace WebsitePanel.Providers.OS // Synchronizing FolderGraph GetFolderGraph(string path); void ExecuteSyncActions(FileSyncAction[] actions); + void SetQuotaLimitOnFolder(string cmdFilePath, string virtualFileClusterName, string folderPath, string quotaLimit, int mode, string wmiUserName, string wmiPassword); } } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj index 3fed47eb..137151d2 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj @@ -92,6 +92,11 @@ + + True + True + Settings.settings + @@ -312,6 +317,10 @@ + + SettingsSingleFileGenerator + Settings.Designer.cs + diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2003/Windows2003.cs b/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2003/Windows2003.cs index f251bd66..0965df57 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2003/Windows2003.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2003/Windows2003.cs @@ -209,6 +209,17 @@ namespace WebsitePanel.Providers.OS SecurityUtils.GrantGroupNtfsPermissions(path, users, resetChildPermissions, ServerSettings, usersOU, null); } + + public virtual void SetQuotaLimitOnFolder(string cmdFilePath, string virtualFileClusterName, string folderPath, string quotaLimit, int mode, string wmiUserName, string wmiPassword) + { + FileUtils.SetQuotaLimitOnFolder(cmdFilePath, virtualFileClusterName, folderPath, quotaLimit, mode, wmiUserName, wmiPassword); + } + + public static void DeleteDirRecursive(DirectoryInfo treeRoot) + { + FileUtils.DeleteDirectoryRecursive(treeRoot); + } + #endregion #region ODBC DSNs diff --git a/WebsitePanel/Sources/WebsitePanel.Server.Client/OperatingSystemProxy.cs b/WebsitePanel/Sources/WebsitePanel.Server.Client/OperatingSystemProxy.cs index f40b6d59..d641b6f1 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server.Client/OperatingSystemProxy.cs +++ b/WebsitePanel/Sources/WebsitePanel.Server.Client/OperatingSystemProxy.cs @@ -61,6 +61,8 @@ namespace WebsitePanel.Providers.OS { private System.Threading.SendOrPostCallback CreatePackageFolderOperationCompleted; private System.Threading.SendOrPostCallback FileExistsOperationCompleted; + + private System.Threading.SendOrPostCallback SetQuotaLimitOnFolderOperationCompleted; private System.Threading.SendOrPostCallback DirectoryExistsOperationCompleted; @@ -131,7 +133,8 @@ namespace WebsitePanel.Providers.OS { private System.Threading.SendOrPostCallback UpdateDSNOperationCompleted; private System.Threading.SendOrPostCallback DeleteDSNOperationCompleted; - + + /// public OperatingSystem() { this.Url = "http://localhost/Server/OperatingSystem.asmx"; @@ -142,6 +145,8 @@ namespace WebsitePanel.Providers.OS { /// public event FileExistsCompletedEventHandler FileExistsCompleted; + + public event SetQuotaLimitOnFolderCompletedEventHandler SetQuotaLimitOnFolderCompleted; /// public event DirectoryExistsCompletedEventHandler DirectoryExistsCompleted; @@ -331,6 +336,56 @@ namespace WebsitePanel.Providers.OS { this.FileExistsCompleted(this, new FileExistsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); } } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/server/SetQuotaLimitOnFolder", RequestNamespace = "http://smbsaas/websitepanel/server/", ResponseNamespace = "http://smbsaas/websitepanel/server/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] + public bool SetQuotaLimitOnFolder(string cmdFilePath, string virtualFileClusterName, string folderPath, string quotaLimit, int mode, string wmiUserName, string wmiPassword) + { + object[] results = this.Invoke("SetQuotaLimitOnFolder", new object[] { + cmdFilePath, virtualFileClusterName, folderPath, quotaLimit, mode, wmiUserName, wmiPassword}); + return ((bool)(results[0])); + } + + /// + public System.IAsyncResult BeginSetQuotaLimitOnFolder(string cmdFilePath, string virtualFileClusterName, string folderPath, string quotaLimit, int mode, string wmiUserName, string wmiPassword, System.AsyncCallback callback, object asyncState) + { + return this.BeginInvoke("SetQuotaLimitOnFolder", new object[] { + cmdFilePath, virtualFileClusterName, folderPath, quotaLimit, mode, wmiUserName, wmiPassword}, callback, asyncState); + } + + /// + public bool EndSetQuotaLimitOnFolder(System.IAsyncResult asyncResult) + { + object[] results = this.EndInvoke(asyncResult); + return ((bool)(results[0])); + } + + /// + public void SetQuotaLimitOnFolderAsync(string cmdFilePath, string virtualFileClusterName, string folderPath, string quotaLimit, int mode, string wmiUserName, string wmiPassword) + { + this.SetQuotaLimitOnFolderAsync(cmdFilePath, virtualFileClusterName, folderPath, quotaLimit, mode, wmiUserName, wmiPassword, null); + } + + /// + public void SetQuotaLimitOnFolderAsync(string cmdFilePath, string virtualFileClusterName, string folderPath, string quotaLimit, int mode, string wmiUserName, string wmiPassword, object userState) + { + if ((this.FileExistsOperationCompleted == null)) + { + this.FileExistsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnFileExistsOperationCompleted); + } + this.InvokeAsync("SetQuotaLimitOnFolder", new object[] { + cmdFilePath, virtualFileClusterName, folderPath, quotaLimit, mode, wmiUserName, wmiPassword}, this.SetQuotaLimitOnFolderOperationCompleted, userState); + } + + private void OnSetQuotaLimitOnFolderOperationCompleted(object arg) + { + if ((this.SetQuotaLimitOnFolderCompleted != null)) + { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.SetQuotaLimitOnFolderCompleted(this, new SetQuotaLimitOnFolderCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } /// [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] @@ -1899,6 +1954,36 @@ namespace WebsitePanel.Providers.OS { } } } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42")] + public delegate void SetQuotaLimitOnFolderCompletedEventHandler(object sender, SetQuotaLimitOnFolderCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class SetQuotaLimitOnFolderCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs + { + + private object[] results; + + internal SetQuotaLimitOnFolderCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) + { + this.results = results; + } + + /// + public bool Result + { + get + { + this.RaiseExceptionIfNecessary(); + return ((bool)(this.results[0])); + } + } + } /// [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42")] diff --git a/WebsitePanel/Sources/WebsitePanel.Server.Utils/FileUtils.cs b/WebsitePanel/Sources/WebsitePanel.Server.Utils/FileUtils.cs index f30354a5..77d6d45e 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server.Utils/FileUtils.cs +++ b/WebsitePanel/Sources/WebsitePanel.Server.Utils/FileUtils.cs @@ -37,6 +37,7 @@ using System.Collections.Generic; using System.Reflection; using Ionic.Zip; using WebsitePanel.Providers.OS; +using System.Management; namespace WebsitePanel.Providers.Utils { @@ -844,6 +845,121 @@ namespace WebsitePanel.Providers.Utils conn, null); cat = null; } + + public static void DeleteDirectoryRecursive(DirectoryInfo treeRoot) + { + if (treeRoot.Exists) + { + + DirectoryInfo[] dirs = treeRoot.GetDirectories(); + while (dirs.Length > 0) + { + foreach (DirectoryInfo dir in dirs) + DeleteDirectoryRecursive(dir); + + dirs = treeRoot.GetDirectories(); + } + + // DELETE THE FILES UNDER THE CURRENT ROOT + string[] files = Directory.GetFiles(treeRoot.FullName); + foreach (string file in files) + { + File.SetAttributes(file, FileAttributes.Normal); + File.Delete(file); + } + + Directory.Delete(treeRoot.FullName, true); + } + + } + + public static void SetQuotaLimitOnFolder(string cmdFilePath, string virtualFileClusterName, string folderPath, string quotaLimit, int mode, string wmiUserName, string wmiPassword) + { + try + { + string[] splits = folderPath.Split('\\'); + if (splits.Length > 0) + { + // Creating the BAT file + FileStream fs = File.Create(cmdFilePath); + if (fs != null) + { + fs.Close(); + fs.Dispose(); + } + + StreamWriter swr = new StreamWriter(cmdFilePath); + + if (swr != null) + { + swr.WriteLine(@"cd c:\windows\system32"); + + string[] shareDrive = { }; + string sharePath = String.Empty; + + if (splits.Length > 4) + { + // Check the share name if it's not an empty string + if (splits[3].Length > 0) + shareDrive = splits[3].Split('_'); + + // Form the share physicalPath + if (shareDrive.Length == 2) + sharePath = shareDrive[1] + @":\" + splits[3]; + + if (splits.Length == 7 && !quotaLimit.Equals(String.Empty)) + { + splits[6] = "wwwroot"; + + switch (mode) + { + // Set + case 0: swr.WriteLine(@"dirquota quota add /path:" + sharePath + @"\" + splits[4] + @"\" + splits[5] + @"\" + splits[6] + @" /limit:" + quotaLimit + @" /remote:" + splits[2]); + break; + + // Modify + case 1: swr.WriteLine(@"dirquota quota modify /path:" + sharePath + @"\" + splits[4] + @"\" + splits[5] + @"\" + splits[6] + @" /limit:" + quotaLimit + @" /remote:" + splits[2]); + break; + } + } + + + } + swr.Flush(); + swr.Close(); + swr.Dispose(); + } + + ConnectionOptions connOptions = new ConnectionOptions(); + + if (wmiUserName.Length > 0) + { + connOptions.Username = wmiUserName; + connOptions.Password = wmiPassword; + } + + connOptions.Impersonation = ImpersonationLevel.Impersonate; + + connOptions.EnablePrivileges = true; + + ManagementScope manScope = + new ManagementScope(String.Format(@"\\{0}\ROOT\CIMV2", virtualFileClusterName), connOptions); + manScope.Connect(); + + ObjectGetOptions objectGetOptions = new ObjectGetOptions(); + ManagementPath managementPath = new ManagementPath("Win32_Process"); + ManagementClass processClass = new ManagementClass(manScope, managementPath, objectGetOptions); + + ManagementBaseObject inParams = processClass.GetMethodParameters("Create"); + inParams["CommandLine"] = cmdFilePath; + ManagementBaseObject outParams = processClass.InvokeMethod("Create", inParams, null); + + } + } + catch + { } + } + #region Advanced Delete /// /// Deletes the specified file. diff --git a/WebsitePanel/Sources/WebsitePanel.Server/OperatingSystem.asmx.cs b/WebsitePanel/Sources/WebsitePanel.Server/OperatingSystem.asmx.cs index e258900a..3e24a15e 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server/OperatingSystem.asmx.cs +++ b/WebsitePanel/Sources/WebsitePanel.Server/OperatingSystem.asmx.cs @@ -533,6 +533,23 @@ namespace WebsitePanel.Server throw; } } + + + [WebMethod, SoapHeader("settings")] + public void SetQuotaLimitOnFolder(string cmdFilePath, string virtualFileClusterName, string folderPath, string quotaLimit, int mode, string wmiUserName, string wmiPassword) + { + try + { + Log.WriteStart("'{0}' SetQuotaLimitOnFolder", ProviderSettings.ProviderName); + OsProvider.SetQuotaLimitOnFolder(cmdFilePath, virtualFileClusterName, folderPath, quotaLimit, mode, wmiUserName, wmiPassword); + Log.WriteEnd("'{0}' SetQuotaLimitOnFolder", ProviderSettings.ProviderName); + } + catch (Exception ex) + { + Log.WriteError(String.Format("'{0}' SetQuotaLimitOnFolder", ProviderSettings.ProviderName), ex); + throw; + } + } #endregion #region Synchronizing diff --git a/WebsitePanel/Sources/WebsitePanel.Server/Web.config b/WebsitePanel/Sources/WebsitePanel.Server/Web.config index 48568b3a..f4c59fb4 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server/Web.config +++ b/WebsitePanel/Sources/WebsitePanel.Server/Web.config @@ -44,7 +44,7 @@ - + diff --git a/WebsitePanel/Sources/WebsitePanel.Server/WebsitePanel.Server.csproj b/WebsitePanel/Sources/WebsitePanel.Server/WebsitePanel.Server.csproj index 890ebc21..5c4731db 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server/WebsitePanel.Server.csproj +++ b/WebsitePanel/Sources/WebsitePanel.Server/WebsitePanel.Server.csproj @@ -20,6 +20,10 @@ v3.5 false + + + + true @@ -231,6 +235,7 @@ + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/WebsitePanel.WebPortal.csproj b/WebsitePanel/Sources/WebsitePanel.WebPortal/WebsitePanel.WebPortal.csproj index c93b1a73..e852620d 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/WebsitePanel.WebPortal.csproj +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/WebsitePanel.WebPortal.csproj @@ -241,6 +241,7 @@ +