public void TC001_ConfigureApplicationTest() { //Arrange IISPlugin target = new IISPlugin(); ApplicationVariable[] appVariables = new ApplicationVariable[] { new ApplicationVariable() { Name = "VCAP_PLUGIN_STAGING_INFO", Value=@"{""assembly"":""Uhuru.CloudFoundry.DEA.Plugins.dll"",""class_name"":""Uhuru.CloudFoundry.DEA.Plugins.IISPlugin"",""logs"":{""app_error"":""logs/stderr.log"",""dea_error"":""logs/err.log"",""startup"":""logs/startup.log"",""app"":""logs/stdout.log""},""auto_wire_templates"":{""mssql-2008"":""Data Source={host},{port};Initial Catalog={name};User Id={user};Password={password};MultipleActiveResultSets=true"",""mysql-5.1"":""server={host};port={port};Database={name};Uid={user};Pwd={password};""}}" }, new ApplicationVariable() { Name = "VCAP_APPLICATION", Value=@"{""instance_id"":""646c477f54386d8afb279ec2f990a823"",""instance_index"":0,""name"":""sinatra_env_test_app"",""uris"":[""sinatra_env_test_app.uhurucloud.net""],""users"":[""*****@*****.**""],""version"":""c394f661a907710b8a8bb70b84ff0c83354dbbed-1"",""start"":""2011-12-07 14:40:12 +0200"",""runtime"":""iis"",""state_timestamp"":1323261612,""port"":51202,""limits"":{""fds"":256,""mem"":67108864,""disk"":2147483648},""host"":""192.168.1.117""}" }, new ApplicationVariable() { Name = "VCAP_SERVICES", Value=@"{""mssql-2008"":[{""name"":""mssql-b24a2"",""label"":""mssql-2008"",""plan"":""free"",""tags"":[""mssql"",""2008"",""relational""],""credentials"":{""name"":""D4Tac4c307851cfe495bb829235cd384f094"",""username"":""US3RTfqu78UpPM5X"",""user"":""US3RTfqu78UpPM5X"",""password"":""P4SSdCGxh2gYjw54"",""hostname"":""192.168.1.3"",""port"":1433,""bind_opts"":{}}}]}" }, new ApplicationVariable() { Name = "VCAP_APP_HOST", Value=@"192.168.1.118" }, new ApplicationVariable() { Name = "VCAP_APP_PORT", Value=@"65498" }, new ApplicationVariable() { Name = "VCAP_WINDOWS_USER_PASSWORD", Value = password }, new ApplicationVariable() { Name = "VCAP_WINDOWS_USER", Value = user }, new ApplicationVariable() { Name = "HOME", Value=TestUtil.CopyFolderToTemp(testAppLoc) } }; Exception exception = null; //Act try { target.ConfigureApplication(appVariables); } catch (Exception ex) { exception = ex; } //Assert Assert.IsNull(exception, "Exception thrown"); }
/// <summary> /// Initializes a new instance of the <see cref="ApplicationParsedData"/> class. /// </summary> /// <param name="appInfo">The app info.</param> /// <param name="runtime">The runtime.</param> /// <param name="variables">The variables.</param> /// <param name="services">The services.</param> /// <param name="urls">The URLs.</param> /// <param name="logFilePath">The log file path.</param> /// <param name="errorLogFilePath">The error log file path.</param> /// <param name="startupLogFilePath">The startup log file path.</param> /// <param name="autoWireTemplates">A list of connection string templates for services.</param> public ApplicationParsedData( ApplicationInfo appInfo, string runtime, ApplicationVariable[] variables, ApplicationService[] services, string[] urls, string logFilePath, string errorLogFilePath, string startupLogFilePath, Dictionary<string, string> autoWireTemplates) { this.appInfo = appInfo; this.runtime = runtime; this.variables = variables; this.services = services; this.logFilePath = logFilePath; this.errorLogFilePath = errorLogFilePath; this.startupLogFilePath = startupLogFilePath; this.autoWireTemplates = autoWireTemplates; this.appUrls = urls; }
public void GetParsedDataTest() { ApplicationVariable[] appVariables = new ApplicationVariable[] { new ApplicationVariable() { Name = "VCAP_PLUGIN_STAGING_INFO", Value=@"{""assembly"":""Uhuru.CloudFoundry.DEA.Plugins.dll"",""class_name"":""Uhuru.CloudFoundry.DEA.Plugins.IISPlugin"",""logs"":{""app_error"":""logs/stderr.log"",""dea_error"":""logs/err.log"",""startup"":""logs/startup.log"",""app"":""logs/stdout.log""},""auto_wire_templates"":{""mssql-2008"":""Data Source={host},{port};Initial Catalog={name};User Id={user};Password={password};MultipleActiveResultSets=true"",""mysql-5.1"":""server={host};port={port};Database={name};Uid={user};Pwd={password};""}}" }, new ApplicationVariable() { Name = "VCAP_APPLICATION", Value=@"{""instance_id"":""646c477f54386d8afb279ec2f990a823"",""instance_index"":0,""name"":""sinatra_env_test_app"",""uris"":[""sinatra_env_test_app.uhurucloud.net""],""users"":[""*****@*****.**""],""version"":""c394f661a907710b8a8bb70b84ff0c83354dbbed-1"",""start"":""2011-12-07 14:40:12 +0200"",""runtime"":""iis"",""state_timestamp"":1323261612,""port"":51202,""limits"":{""fds"":256,""mem"":67108864,""disk"":2147483648},""host"":""192.168.1.117""}" }, new ApplicationVariable() { Name = "VCAP_SERVICES", Value=@"{""mssql-2008"":[{""name"":""mssql-b24a2"",""label"":""mssql-2008"",""plan"":""free"",""tags"":[""mssql"",""2008"",""relational""],""credentials"":{""name"":""D4Tac4c307851cfe495bb829235cd384f094"",""username"":""US3RTfqu78UpPM5X"",""user"":""US3RTfqu78UpPM5X"",""password"":""P4SSdCGxh2gYjw54"",""hostname"":""192.168.1.3"",""port"":1433,""bind_opts"":{}}}]}" }, new ApplicationVariable() { Name = "VCAP_APP_HOST", Value=@"192.168.1.118" }, new ApplicationVariable() { Name = "VCAP_APP_PORT", Value=@"65498" }, new ApplicationVariable() { Name = "VCAP_WINDOWS_USER_PASSWORD", Value=@"password" }, new ApplicationVariable() { Name = "VCAP_WINDOWS_USER", Value=@"cfuser" }, new ApplicationVariable() { Name = "HOME", Value=@"c:\droplets\mydroplet" } }; ApplicationParsedData actual; actual = PluginHelper.GetParsedData(appVariables); Assert.AreEqual("646c477f54386d8afb279ec2f990a823", actual.AppInfo.InstanceId); Assert.AreEqual("192.168.1.118", actual.AppInfo.LocalIP); Assert.AreEqual("sinatra_env_test_app", actual.AppInfo.Name); Assert.AreEqual(@"c:\droplets\mydroplet\app", actual.AppInfo.Path); Assert.AreEqual(65498, actual.AppInfo.Port); Assert.AreEqual("cfuser", actual.AppInfo.WindowsUserName); Assert.AreEqual("password", actual.AppInfo.WindowsPassword); Assert.AreEqual(2, actual.AutoWireTemplates.Count); Assert.AreEqual(@"c:\droplets\mydroplet\logs/stderr.log", actual.ErrorLogFilePath); Assert.AreEqual(@"c:\droplets\mydroplet\logs/stdout.log", actual.LogFilePath); Assert.AreEqual("iis", actual.Runtime); Assert.AreEqual("192.168.1.3", actual.GetServices()[0].Host); Assert.AreEqual("D4Tac4c307851cfe495bb829235cd384f094", actual.GetServices()[0].InstanceName); Assert.AreEqual("mssql-b24a2", actual.GetServices()[0].Name); Assert.AreEqual("P4SSdCGxh2gYjw54", actual.GetServices()[0].Password); Assert.AreEqual("free", actual.GetServices()[0].Plan); Assert.AreEqual(1433, actual.GetServices()[0].Port); Assert.AreEqual("mssql-2008", actual.GetServices()[0].ServiceLabel); Assert.AreEqual(3, actual.GetServices()[0].GetServiceTags().Length); Assert.AreEqual("US3RTfqu78UpPM5X", actual.GetServices()[0].User); Assert.AreEqual(@"c:\droplets\mydroplet\logs/startup.log", actual.StartupLogFilePath); }
/// <summary> /// sets the initial data for an application /// </summary> /// <param name="variables">All variables needed to run the application.</param> public void ConfigureApplication(ApplicationVariable[] variables) { try { ApplicationParsedData parsedData = PluginHelper.GetParsedData(variables); this.startupLogger = new FileLogger(parsedData.StartupLogFilePath); this.appName = RemoveSpecialCharacters(parsedData.AppInfo.Name) + parsedData.AppInfo.Port.ToString(CultureInfo.InvariantCulture); this.appPath = parsedData.AppInfo.Path; this.applicationInfo = parsedData.AppInfo; this.autoWireTemplates = parsedData.AutoWireTemplates; this.aspDotNetVersion = this.GetAppVersion(this.applicationInfo); this.cpuTarget = this.GetCpuTarget(this.applicationInfo); this.AutowireApp(parsedData.AppInfo, variables, parsedData.GetServices(), parsedData.LogFilePath, parsedData.ErrorLogFilePath); } catch (Exception ex) { this.startupLogger.Error(ex.ToString()); throw; } }
/// <summary> /// Auto-wires the application variables and the log file path in the web.config file. /// </summary> /// <param name="configPath">The config file path.</param> /// <param name="variables">The variables.</param> /// <param name="logFilePath">The log file path.</param> /// <param name="errorLogFilePath">The error log file path.</param> private void SetApplicationVariables(string configPath, ApplicationVariable[] variables, string logFilePath, string errorLogFilePath) { this.startupLogger.Info(Strings.SettingUpApplicationVariables); var configFile = new FileInfo(configPath); var vdm = new System.Web.Configuration.VirtualDirectoryMapping(configFile.DirectoryName, true, configFile.Name); var wcfm = new System.Web.Configuration.WebConfigurationFileMap(); wcfm.VirtualDirectories.Add("/", vdm); System.Configuration.Configuration webConfig = System.Web.Configuration.WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/"); bool hasUhuruLogFile = false; bool hasUhuruErrorLogFile = false; foreach (ApplicationVariable var in variables) { if (var.Name == "UHURU_LOG_FILE") { hasUhuruLogFile = true; } if (var.Name == "UHURU_ERROR_LOG_FILE") { hasUhuruErrorLogFile = true; } if (webConfig.AppSettings.Settings[var.Name] == null) { webConfig.AppSettings.Settings.Add(var.Name, var.Value); } else { webConfig.AppSettings.Settings[var.Name].Value = var.Value; } } if (!hasUhuruLogFile) { if (webConfig.AppSettings.Settings["UHURU_LOG_FILE"] == null) { webConfig.AppSettings.Settings.Add("UHURU_LOG_FILE", logFilePath); } else { webConfig.AppSettings.Settings["UHURU_LOG_FILE"].Value = logFilePath; } } if (!hasUhuruErrorLogFile) { if (webConfig.AppSettings.Settings["UHURU_ERROR_LOG_FILE"] == null) { webConfig.AppSettings.Settings.Add("UHURU_ERROR_LOG_FILE", errorLogFilePath); } else { webConfig.AppSettings.Settings["UHURU_ERROR_LOG_FILE"].Value = errorLogFilePath; } } this.startupLogger.Info(Strings.DoneSettingUpApplication); webConfig.Save(); }
/// <summary> /// Autowires the service connections and ASP.NET health monitoring in the application's web.config /// </summary> /// <param name="appInfo">The application info structure.</param> /// <param name="variables">All application variables.</param> /// <param name="services">The services.</param> /// <param name="logFilePath">The ASP.NET "Heartbeat" and "Lifetime Events" log file path.</param> /// <param name="errorLogFilePath">The ASP.NET "All Errors" events log file path.</param> private void AutowireApp(ApplicationInfo appInfo, ApplicationVariable[] variables, ApplicationService[] services, string logFilePath, string errorLogFilePath) { this.startupLogger.Info(Strings.StartingApplicationAutoWiring); List<ApplicationVariable> varList = variables.ToList<ApplicationVariable>(); ApplicationVariable applicationVariable = new ApplicationVariable(); applicationVariable.Name = "TUNNEL_NET_TCP_PORT"; applicationVariable.Value = NetworkInterface.GrabEphemeralPort().ToString(CultureInfo.InvariantCulture); varList.Add(applicationVariable); variables = varList.ToArray(); // get all config files string[] allConfigFiles = Directory.GetFiles(appInfo.Path, "*.config", SearchOption.AllDirectories); foreach (string configFile in allConfigFiles) { if (File.Exists(configFile)) { string configFileContents = File.ReadAllText(configFile); if (services != null) { Dictionary<string, string> connections = new Dictionary<string, string>(); Dictionary<string, string> connValues = new Dictionary<string, string>(); foreach (ApplicationService service in services) { string key = service.ServiceLabel; string template = string.Empty; if (this.autoWireTemplates.TryGetValue(key, out template)) { template = template.Replace(Strings.Host, service.Host); template = template.Replace(Strings.Port, service.Port.ToString(CultureInfo.InvariantCulture)); template = template.Replace(Strings.Name, service.InstanceName); template = template.Replace(Strings.User, service.User); template = template.Replace(Strings.Password, service.Password); connections[string.Format(CultureInfo.InvariantCulture, "{{{0}#{1}}}", key, service.Name)] = template; } char[] charsToTrim = { '{', '}' }; connValues.Add(string.Format(CultureInfo.InvariantCulture, "{{{0}#{1}}}", service.Name, Strings.User.Trim(charsToTrim)), service.User); connValues.Add(string.Format(CultureInfo.InvariantCulture, "{{{0}#{1}}}", service.Name, Strings.Host.Trim(charsToTrim)), service.Host); connValues.Add(string.Format(CultureInfo.InvariantCulture, "{{{0}#{1}}}", service.Name, Strings.Port.Trim(charsToTrim)), service.Port.ToString(CultureInfo.InvariantCulture)); connValues.Add(string.Format(CultureInfo.InvariantCulture, "{{{0}#{1}}}", service.Name, Strings.Password.Trim(charsToTrim)), service.Password); connValues.Add(string.Format(CultureInfo.InvariantCulture, "{{{0}#{1}}}", service.Name, Strings.Name.Trim(charsToTrim)), service.InstanceName); } foreach (string con in connections.Keys) { this.startupLogger.Info(Strings.ConfiguringService + con); configFileContents = configFileContents.Replace(con, connections[con]); } foreach (string key in connValues.Keys) { this.startupLogger.Info(string.Format(CultureInfo.InvariantCulture, Strings.ConfiguringServiceValue, key)); configFileContents = configFileContents.Replace(key, connValues[key]); } } File.WriteAllText(configFile, configFileContents); } } string webConfigFile = Path.Combine(appInfo.Path, "web.config"); if (File.Exists(webConfigFile)) { this.SetApplicationVariables(webConfigFile, variables, logFilePath, errorLogFilePath); this.startupLogger.Info(Strings.SavedConfigurationFile); this.startupLogger.Info(Strings.SettingUpLogging); string appDir = Path.GetDirectoryName(webConfigFile); string binDir = Path.Combine(appDir, "bin"); string assemblyFile = typeof(LogFileWebEventProvider).Assembly.Location; string destinationAssemblyFile = Path.Combine(binDir, Path.GetFileName(assemblyFile)); Directory.CreateDirectory(binDir); File.Copy(assemblyFile, destinationAssemblyFile, true); this.startupLogger.Info(Strings.CopiedLoggingBinariesToBin); SiteConfig siteConfiguration = new SiteConfig(appDir, true); HealthMonRewire healthMon = new HealthMonRewire(); healthMon.Register(siteConfiguration); siteConfiguration.Rewire(false); siteConfiguration.CommitChanges(); this.startupLogger.Info(Strings.UpdatedLoggingConfiguration); DirectoryInfo errorLogDir = new DirectoryInfo(Path.GetDirectoryName(errorLogFilePath)); DirectoryInfo logDir = new DirectoryInfo(Path.GetDirectoryName(logFilePath)); DirectorySecurity errorLogDirSecurity = errorLogDir.GetAccessControl(); DirectorySecurity logDirSecurity = logDir.GetAccessControl(); errorLogDirSecurity.SetAccessRule( new FileSystemAccessRule( appInfo.WindowsUserName, FileSystemRights.Write | FileSystemRights.Read | FileSystemRights.Delete | FileSystemRights.Modify | FileSystemRights.CreateFiles, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)); logDirSecurity.SetAccessRule( new FileSystemAccessRule( appInfo.WindowsUserName, FileSystemRights.Write | FileSystemRights.Read | FileSystemRights.Delete | FileSystemRights.Modify | FileSystemRights.CreateFiles, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)); errorLogDir.SetAccessControl(errorLogDirSecurity); logDir.SetAccessControl(logDirSecurity); } }
/// <summary> /// recovers a running application /// </summary> /// <param name="variables">All variables needed to run the application.</param> public void RecoverApplication(ApplicationVariable[] variables) { try { ApplicationParsedData parsedData = PluginHelper.GetParsedData(variables); this.startupLogger = new FileLogger(parsedData.StartupLogFilePath); this.appName = RemoveSpecialCharacters(parsedData.AppInfo.Name) + parsedData.AppInfo.Port.ToString(CultureInfo.InvariantCulture); this.appPath = parsedData.AppInfo.Path; this.applicationInfo = parsedData.AppInfo; this.autoWireTemplates = parsedData.AutoWireTemplates; } catch (Exception ex) { this.startupLogger.Error(ex.ToString()); throw; } }
public void TC002_StartWebAppTest() { //Arrange IISPlugin target = new IISPlugin(); int port = Uhuru.Utilities.NetworkInterface.GrabEphemeralPort(); ApplicationVariable[] appVariables = new ApplicationVariable[] { new ApplicationVariable() { Name = "VCAP_PLUGIN_STAGING_INFO", Value=@"{""assembly"":""Uhuru.CloudFoundry.DEA.Plugins.dll"",""class_name"":""Uhuru.CloudFoundry.DEA.Plugins.IISPlugin"",""logs"":{""app_error"":""logs/stderr.log"",""dea_error"":""logs/err.log"",""startup"":""logs/startup.log"",""app"":""logs/stdout.log""},""auto_wire_templates"":{""mssql-2008"":""Data Source={host},{port};Initial Catalog={name};User Id={user};Password={password};MultipleActiveResultSets=true"",""mysql-5.1"":""server={host};port={port};Database={name};Uid={user};Pwd={password};""}}" }, new ApplicationVariable() { Name = "VCAP_APPLICATION", Value=@"{""instance_id"":""" + Guid.NewGuid().ToString() + @""",""instance_index"":0,""name"":""MyTestApp"",""uris"":[""sinatra_env_test_app.uhurucloud.net""],""users"":[""*****@*****.**""],""version"":""c394f661a907710b8a8bb70b84ff0c83354dbbed-1"",""start"":""2011-12-07 14:40:12 +0200"",""runtime"":""iis"",""state_timestamp"":1323261612,""port"":51202,""limits"":{""fds"":256,""mem"":67108864,""disk"":2147483648},""host"":""192.168.1.117""}" }, new ApplicationVariable() { Name = "VCAP_SERVICES", Value=@"{""mssql-2008"":[{""name"":""mssql-b24a2"",""label"":""mssql-2008"",""plan"":""free"",""tags"":[""mssql"",""2008"",""relational""],""credentials"":{""name"":""D4Tac4c307851cfe495bb829235cd384f094"",""username"":""US3RTfqu78UpPM5X"",""user"":""US3RTfqu78UpPM5X"",""password"":""P4SSdCGxh2gYjw54"",""hostname"":""192.168.1.3"",""port"":1433,""bind_opts"":{}}}]}" }, new ApplicationVariable() { Name = "VCAP_APP_HOST", Value=TestUtil.GetLocalIp() }, new ApplicationVariable() { Name = "VCAP_APP_PORT", Value = port.ToString() }, new ApplicationVariable() { Name = "VCAP_WINDOWS_USER_PASSWORD", Value = password }, new ApplicationVariable() { Name = "VCAP_WINDOWS_USER", Value = user }, new ApplicationVariable() { Name = "HOME", Value=TestUtil.CopyFolderToTemp(testAppLoc) } }; //Act target.ConfigureApplication(appVariables); target.StartApplication(); //Assert WebClient client = new WebClient(); string html = client.DownloadString("http://localhost:" + port.ToString()); Assert.IsTrue(html.Contains("My ASP.NET Application")); target.StopApplication(); try { html = client.DownloadString("http://localhost:" + port.ToString()); } catch { return; } Assert.Fail(); }
public void TC003_MultipleWebApps() { List<ApplicationVariable[]> appInfos = new List<ApplicationVariable[]>(); List<IISPlugin> plugins = new List<IISPlugin>(); List<Thread> threadsStart = new List<Thread>(); List<Thread> threadsStop = new List<Thread>(); for (int i = 0; i < 20; i++) { int port = Uhuru.Utilities.NetworkInterface.GrabEphemeralPort(); ApplicationVariable[] appInfo = new ApplicationVariable[] { new ApplicationVariable() { Name = "VCAP_PLUGIN_STAGING_INFO", Value=@"{""assembly"":""Uhuru.CloudFoundry.DEA.Plugins.dll"",""class_name"":""Uhuru.CloudFoundry.DEA.Plugins.IISPlugin"",""logs"":{""app_error"":""logs/stderr.log"",""dea_error"":""logs/err.log"",""startup"":""logs/startup.log"",""app"":""logs/stdout.log""},""auto_wire_templates"":{""mssql-2008"":""Data Source={host},{port};Initial Catalog={name};User Id={user};Password={password};MultipleActiveResultSets=true"",""mysql-5.1"":""server={host};port={port};Database={name};Uid={user};Pwd={password};""}}" }, new ApplicationVariable() { Name = "VCAP_APPLICATION", Value=@"{""instance_id"":""" + Guid.NewGuid().ToString() + @""",""instance_index"":0,""name"":""MyTestApp"",""uris"":[""sinatra_env_test_app.uhurucloud.net""],""users"":[""*****@*****.**""],""version"":""c394f661a907710b8a8bb70b84ff0c83354dbbed-1"",""start"":""2011-12-07 14:40:12 +0200"",""runtime"":""iis"",""state_timestamp"":1323261612,""port"":51202,""limits"":{""fds"":256,""mem"":67108864,""disk"":2147483648},""host"":""192.168.1.117""}" }, new ApplicationVariable() { Name = "VCAP_SERVICES", Value=@"{""mssql-2008"":[{""name"":""mssql-b24a2"",""label"":""mssql-2008"",""plan"":""free"",""tags"":[""mssql"",""2008"",""relational""],""credentials"":{""name"":""D4Tac4c307851cfe495bb829235cd384f094"",""username"":""US3RTfqu78UpPM5X"",""user"":""US3RTfqu78UpPM5X"",""password"":""P4SSdCGxh2gYjw54"",""hostname"":""192.168.1.3"",""port"":1433,""bind_opts"":{}}}]}" }, new ApplicationVariable() { Name = "VCAP_APP_HOST", Value=TestUtil.GetLocalIp() }, new ApplicationVariable() { Name = "VCAP_APP_PORT", Value = port.ToString() }, new ApplicationVariable() { Name = "VCAP_WINDOWS_USER_PASSWORD", Value = password }, new ApplicationVariable() { Name = "VCAP_WINDOWS_USER", Value = user }, new ApplicationVariable() { Name = "HOME", Value=TestUtil.CopyFolderToTemp(testAppLoc) } }; appInfos.Add(appInfo); plugins.Add(new IISPlugin()); } for (int i = 0; i < 20; i++) { threadsStart.Add(new Thread(new ParameterizedThreadStart(delegate(object data) { try { IISPlugin target = plugins[(int)data]; target.ConfigureApplication(appInfos[(int)data]); target.StartApplication(); } catch (Exception ex) { Logger.Fatal(ex.ToString()); } }))); } for (int i = 0; i < threadsStart.Count; i++) { Thread thread = threadsStart[i]; thread.Start(i); } foreach (Thread thread in threadsStart) { thread.Join(); } foreach (ApplicationVariable[] appInfo in appInfos) { WebClient client = new WebClient(); string html = client.DownloadString("http://localhost:" + appInfo.First(v => v.Name == "VCAP_APP_PORT").Value); Assert.IsTrue(html.Contains("My ASP.NET Application")); } for (int i = 0; i < 20; i++) { threadsStop.Add(new Thread(new ParameterizedThreadStart(delegate(object data) { try { IISPlugin target = plugins[(int)data]; target.StopApplication(); } catch (Exception ex) { Logger.Fatal(ex.ToString()); } }))); } for (int i = 0; i < threadsStop.Count; i++) { Thread thread = threadsStop[i]; thread.Start(i); } foreach (Thread thread in threadsStop) { thread.Join(); } foreach (ApplicationVariable[] appInfo in appInfos) { try { WebClient client = new WebClient(); string html = client.DownloadString("http://localhost:" + appInfo.First(v => v.Name == "VCAP_APP_PORT").Value); Assert.Fail(); } catch { } } }
/// <summary> /// Gets the parsed data for an application. /// </summary> /// <param name="appVariables">The unstructured app variables.</param> /// <returns>An ApplicationParsedData object, that contains structured information about the application.</returns> public static ApplicationParsedData GetParsedData(ApplicationVariable[] appVariables) { if (appVariables == null) { throw new ArgumentNullException("appVariables"); } Dictionary<string, string> variablesHash = new Dictionary<string, string>(appVariables.Length); foreach (ApplicationVariable variable in appVariables) { variablesHash[variable.Name] = variable.Value; } ApplicationVariable[] variables = appVariables; ApplicationInfo appInfo = new ApplicationInfo(); VcapApplication vcapApplication = new VcapApplication(); vcapApplication.FromJsonIntermediateObject(JsonConvertibleObject.DeserializeFromJson(variablesHash[PluginBaseRes.VcapApplicationVariable])); appInfo.InstanceId = vcapApplication.InstanceId; appInfo.LocalIP = variablesHash[PluginBaseRes.VcapAppHostVariable]; appInfo.Name = vcapApplication.Name; appInfo.Path = Path.Combine(variablesHash[PluginBaseRes.HomeVariable], "app"); appInfo.Port = int.Parse(variablesHash[PluginBaseRes.VcapAppPortVariable], CultureInfo.InvariantCulture); appInfo.WindowsPassword = variablesHash[PluginBaseRes.VcapWindowsUserPasswordVariable]; appInfo.WindowsUserName = variablesHash[PluginBaseRes.VcapWindowsUserVariable]; string runtime = vcapApplication.Runtime; string servicesJson = variablesHash[PluginBaseRes.VcapServicesVariable]; Dictionary<string, object[]> vcapProvisionedServices = new Dictionary<string, object[]>(); List<ApplicationService> services = new List<ApplicationService>(); vcapProvisionedServices = JsonConvertibleObject.ObjectToValue<Dictionary<string, object[]>>(JsonConvertibleObject.DeserializeFromJson(servicesJson)); foreach (string serviceLabel in vcapProvisionedServices.Keys) { foreach (object provisionedService in vcapProvisionedServices[serviceLabel]) { VcapProvisionedService service = new VcapProvisionedService(); service.FromJsonIntermediateObject(provisionedService); ApplicationService appService = new ApplicationService( service.Name, string.IsNullOrEmpty(service.Credentials.User) ? service.Credentials.Username : service.Credentials.User, service.Credentials.Password, service.Credentials.Port, service.Plan, service.PlanOptions, string.IsNullOrEmpty(service.Credentials.Hostname) ? service.Credentials.Host : service.Credentials.Hostname, service.Credentials.InstanceName, service.Label, service.Tags); services.Add(appService); } } VcapPluginStagingInfo vcapPluginStagingInfo = new VcapPluginStagingInfo(); vcapPluginStagingInfo.FromJsonIntermediateObject(JsonConvertibleObject.DeserializeFromJson(variablesHash[PluginBaseRes.VcapPluginStagingInfoVariable])); string logFilePath = Path.Combine(variablesHash[PluginBaseRes.HomeVariable], vcapPluginStagingInfo.Logs.AppLog); string errorLogFilePath = Path.Combine(variablesHash[PluginBaseRes.HomeVariable], vcapPluginStagingInfo.Logs.AppErrorLog); string startupLogFilePath = Path.Combine(variablesHash[PluginBaseRes.HomeVariable], vcapPluginStagingInfo.Logs.StartupLog); return new ApplicationParsedData( appInfo, runtime, variables, services.ToArray(), vcapApplication.Urls, logFilePath, errorLogFilePath, startupLogFilePath, vcapPluginStagingInfo.AutoWireTemplates); }
/// <summary> /// Auto-wires the application variables and the log file path in the web.config file. /// </summary> /// <param name="configFileContents">The config file contents.</param> /// <param name="variables">The variables.</param> /// <param name="logFilePath">The log file path.</param> /// <param name="errorLogFilePath">The error log file path.</param> /// <returns>An xml document ready containing the updated configuration file.</returns> private XmlDocument SetApplicationVariables(string configFileContents, ApplicationVariable[] variables, string logFilePath, string errorLogFilePath) { this.startupLogger.Info(Strings.SettingUpApplicationVariables); XmlDocument doc = new XmlDocument(); doc.LoadXml(configFileContents); XmlNode appSettingsNode = doc.SelectSingleNode("configuration/appSettings"); if (appSettingsNode == null) { appSettingsNode = doc.CreateNode(XmlNodeType.Element, "appSettings", string.Empty); doc.SelectSingleNode("configuration").PrependChild(appSettingsNode); } bool exists = false; bool hasUhuruLogFile = false; bool hasUhuruErrorLogFile = false; foreach (ApplicationVariable var in variables) { exists = false; if (var.Name == "UHURU_LOG_FILE") { hasUhuruLogFile = true; } if (var.Name == "UHURU_ERROR_LOG_FILE") { hasUhuruErrorLogFile = true; } XmlNode n = doc.CreateNode(XmlNodeType.Element, "add", string.Empty); XmlAttribute keyAttr = doc.CreateAttribute("key"); keyAttr.Value = var.Name; XmlAttribute valueAttr = doc.CreateAttribute("value"); valueAttr.Value = var.Value; n.Attributes.Append(keyAttr); n.Attributes.Append(valueAttr); XPathNodeIterator iter = appSettingsNode.CreateNavigator().Select("add"); while (iter.MoveNext()) { string key = iter.Current.GetAttribute("key", string.Empty); if (!string.IsNullOrEmpty(key) && key == var.Name) { exists = true; iter.Current.ReplaceSelf(n.CreateNavigator()); } } if (!exists) { appSettingsNode.AppendChild(n); } } if (!hasUhuruLogFile) { exists = false; XmlNode n = doc.CreateNode(XmlNodeType.Element, "add", string.Empty); XmlAttribute keyAttr = doc.CreateAttribute("key"); keyAttr.Value = "UHURU_LOG_FILE"; XmlAttribute valueAttr = doc.CreateAttribute("value"); valueAttr.Value = logFilePath; n.Attributes.Append(keyAttr); n.Attributes.Append(valueAttr); XPathNodeIterator iter = appSettingsNode.CreateNavigator().Select("add"); while (iter.MoveNext()) { string key = iter.Current.GetAttribute("key", string.Empty); if (!string.IsNullOrEmpty(key) && key == "UHURU_LOG_FILE") { exists = true; iter.Current.ReplaceSelf(n.CreateNavigator()); } } if (!exists) { appSettingsNode.AppendChild(n); } } if (!hasUhuruErrorLogFile) { exists = false; XmlNode n = doc.CreateNode(XmlNodeType.Element, "add", string.Empty); XmlAttribute keyAttr = doc.CreateAttribute("key"); keyAttr.Value = "UHURU_ERROR_LOG_FILE"; XmlAttribute valueAttr = doc.CreateAttribute("value"); valueAttr.Value = errorLogFilePath; n.Attributes.Append(keyAttr); n.Attributes.Append(valueAttr); XPathNodeIterator iter = appSettingsNode.CreateNavigator().Select("add"); while (iter.MoveNext()) { string key = iter.Current.GetAttribute("key", string.Empty); if (!string.IsNullOrEmpty(key) && key == "UHURU_ERROR_LOG_FILE") { exists = true; iter.Current.ReplaceSelf(n.CreateNavigator()); } } if (!exists) { appSettingsNode.AppendChild(n); } } this.startupLogger.Info(Strings.DoneSettingUpApplication); return doc; }
private void AutowireUhurufs(ApplicationInfo appInfo, ApplicationVariable[] variables, ApplicationService[] services, string homeAppPath) { this.startupLogger.Info(Strings.StartingApplicationAutoWiring); Dictionary<string, HashSet<string>> persistentFiles = new Dictionary<string, HashSet<string>>(); foreach (ApplicationVariable var in variables) { if (var.Name.StartsWith("uhurufs_", StringComparison.Ordinal)) { string serviceName = var.Name.Split(new string[] { "uhurufs_" }, 2, StringSplitOptions.RemoveEmptyEntries)[0]; if (!persistentFiles.ContainsKey(serviceName)) { persistentFiles[serviceName] = new HashSet<string>(); } string[] persistedItems = var.Value.Trim(new char[] { '"' }).Split(new char[] { ';', ',', ':' }); foreach (string item in persistedItems) { persistentFiles[serviceName].Add(item.Replace('/', '\\')); } } } foreach (ApplicationService serv in services) { if (serv.ServiceLabel.StartsWith("uhurufs", StringComparison.Ordinal)) { string shareHost = GenerateUhurufsHost(appInfo.InstanceId, serv.InstanceName, serv.User); try { if (!SystemHosts.Exists(shareHost)) { // Note: delete the host after the app is deleted SystemHosts.Add(shareHost, serv.Host); } } catch (ArgumentException) { // If the service host cannot be added to hosts connect shareHost = serv.Host; } string remotePath = string.Format(CultureInfo.InvariantCulture, @"\\{0}\{1}", shareHost, serv.InstanceName); string mountPath = GenerateMountPath(homeAppPath, serv.Name); Directory.CreateDirectory(Path.Combine(mountPath, @"..")); // Add the share users credentials to the application user. // This way the application can use the share directly without invoking `net use` with the credentials. using (new UserImpersonator(appInfo.WindowsUserName, ".", appInfo.WindowsPassword, true)) { SaveCredentials.AddDomainUserCredential(shareHost, serv.User, serv.Password); } // The impersonated user cannot create links // Note: unmount the share after the app is deleted SambaWindowsClient.Mount(remotePath, serv.User, serv.Password); SambaWindowsClient.LinkDirectory(remotePath, mountPath); if (persistentFiles.ContainsKey(serv.Name)) { foreach (string fileSystemItem in persistentFiles[serv.Name]) { try { this.PersistFileSystemItem(appInfo.Path, fileSystemItem, Path.Combine(mountPath, appInfo.Name)); } catch (Exception ex) { this.startupLogger.Error("Failed linking file/directory: {0}. Exception: {1}", fileSystemItem, ex.ToString()); } } } } } }
public void RecoverExistingDroplets() { if (!File.Exists(this.droplets.AppStateFile)) { this.droplets.RecoveredDroplets = true; return; } object[] instances = JsonConvertibleObject.DeserializeFromJsonArray(File.ReadAllText(this.droplets.AppStateFile)); foreach (object obj in instances) { DropletInstance instance = null; try { instance = new DropletInstance(); instance.Properties.FromJsonIntermediateObject(obj); instance.Properties.Orphaned = true; instance.Properties.ResourcesTracked = false; this.monitoring.AddInstanceResources(instance); instance.Properties.StopProcessed = false; instance.JobObject.JobMemoryLimit = instance.Properties.MemoryQuotaBytes; try { instance.LoadPlugin(); instance.Properties.EnvironmentVariables[VcapAppPidVariable] = instance.Properties.ProcessId.ToString(CultureInfo.InvariantCulture); List<ApplicationVariable> appVariables = new List<ApplicationVariable>(); foreach (KeyValuePair<string, string> appEnv in instance.Properties.EnvironmentVariables) { ApplicationVariable appVariable = new ApplicationVariable(); appVariable.Name = appEnv.Key; appVariable.Value = appEnv.Value; appVariables.Add(appVariable); } instance.Plugin.RecoverApplication(appVariables.ToArray()); } catch (Exception ex) { instance.ErrorLog.Error(ex.ToString()); } if (instance.Properties.State == DropletInstanceState.Starting) { this.DetectAppReady(instance); } this.droplets.AddDropletInstance(instance); instance = null; } catch (Exception ex) { Logger.Warning(Strings.ErrorRecoveringDropletWarningMessage, instance.Properties.InstanceId, ex.ToString()); } finally { if (instance != null) { instance.Dispose(); } } } this.droplets.RecoveredDroplets = true; if (this.monitoring.Clients > 0) { Logger.Info(Strings.DeaRecoveredApplications, this.monitoring.Clients); } this.MonitorApps(); this.droplets.ForEach(delegate(DropletInstance instance) { this.RegisterInstanceWithRouter(instance); }); this.SendHeartbeat(); this.droplets.ScheduleSnapshotAppState(); }
private void StartDropletInstance(DropletInstance instance, string sha1, string executableFile, Uri executableUri) { try { string tgzFile = Path.Combine(this.stager.StagedDir, sha1 + ".tgz"); this.stager.StageAppDirectory(executableFile, executableUri, sha1, tgzFile, instance); Logger.Debug(Strings.Downloadcompleate); string starting = string.Format(CultureInfo.InvariantCulture, Strings.StartingUpInstanceOnPort, instance.Properties.LoggingId, instance.Properties.Port); if (!string.IsNullOrEmpty(instance.Properties.DebugMode)) { Logger.Info(starting + Strings.WithDebuggerPort, instance.Properties.DebugPort); } else { Logger.Info(starting); } Logger.Debug(Strings.Clients, this.monitoring.Clients); Logger.Debug(Strings.ReservedMemoryUsageMb, this.monitoring.MemoryReservedMbytes, this.monitoring.MaxMemoryMbytes); List<ApplicationVariable> appVariables = new List<ApplicationVariable>(); try { instance.Lock.EnterWriteLock(); instance.Properties.WindowsPassword = "******" + Credentials.GenerateCredential(); instance.Properties.WindowsUserName = WindowsVCAPUsers.CreateUser(instance.Properties.InstanceId, instance.Properties.WindowsPassword); instance.Properties.EnvironmentVariables.Add(VcapWindowsUserVariable, instance.Properties.WindowsUserName); instance.Properties.EnvironmentVariables.Add(VcapWindowsUserPasswordVariable, instance.Properties.WindowsPassword); instance.Properties.EnvironmentVariables.Add(VcapPluginStagingInfoVariable, File.ReadAllText(Path.Combine(instance.Properties.Directory, "startup"))); foreach (KeyValuePair<string, string> appEnv in instance.Properties.EnvironmentVariables) { ApplicationVariable appVariable = new ApplicationVariable(); appVariable.Name = appEnv.Key; appVariable.Value = appEnv.Value; appVariables.Add(appVariable); } } finally { instance.Lock.ExitWriteLock(); } DateTime start = DateTime.Now; instance.LoadPlugin(); instance.Plugin.ConfigureApplication(appVariables.ToArray()); instance.Plugin.StartApplication(); int pid = instance.Plugin.GetApplicationProcessId(); Logger.Debug(Strings.TookXTimeToLoadConfigureAndStartDebugMessage, (DateTime.Now - start).TotalSeconds); try { instance.Lock.EnterWriteLock(); if (!instance.Properties.StopProcessed) { Logger.Info(Strings.PidAssignedToDroplet, pid, instance.Properties.LoggingId); instance.Properties.ProcessId = pid; this.droplets.ScheduleSnapshotAppState(); } } finally { instance.Lock.ExitWriteLock(); } this.DetectAppReady(instance); } catch (Exception ex) { Logger.Warning(Strings.FailedStagingAppDir, instance.Properties.Directory, instance.Properties.LoggingId, ex.ToString()); try { instance.Lock.EnterWriteLock(); instance.Properties.State = DropletInstanceState.Crashed; instance.Properties.ExitReason = DropletExitReason.Crashed; instance.Properties.StateTimestamp = DateTime.Now; this.StopDroplet(instance); } finally { instance.Lock.ExitWriteLock(); } } }