/// <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; }
/// <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> /// 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> /// 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)); }
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()); } } } } } }