public void WhenBootstrapperRequest_IsWindowsService_ReturnsSuccess()
        {
            var request = new BootstrappingRequest(string.Empty, ComponentType.WindowsService, new Guid(), new Guid(), string.Empty, string.Empty, string.Empty, new CustomProperty[0]);

            var result = new DotNetLog4NetConnector().Bootstrap(request);

            result.ShouldBeSuccessful();
        }
Example #2
0
 public override BootstrappingResult Bootstrap(BootstrappingRequest bootstrappingRequest)
 {
     //Only modify .NET Websites Components that do not belong to the Apprenda Team
     if ((bootstrappingRequest.ComponentType == ComponentType.AspNet |
          bootstrappingRequest.ComponentType == ComponentType.PublicAspNet |
          bootstrappingRequest.ComponentType == ComponentType.WcfService) &&
         !bootstrappingRequest.DevelopmentTeamAlias.Equals("apprenda", StringComparison.InvariantCultureIgnoreCase))
     {
         return(ModifyConfigFiles(bootstrappingRequest));
     }
     else
     {
         return(BootstrappingResult.Success());
     }
 }
Example #3
0
        private static BootstrappingResult ModifyConfigFiles(BootstrappingRequest bootstrappingRequest)
        {
            //Search for all web.config files within the component being deployed
            string[] configFiles = Directory.GetFiles(bootstrappingRequest.ComponentPath, "web.config", SearchOption.AllDirectories);

            foreach (string file in configFiles)
            {
                var result = ModifyXML(bootstrappingRequest, file);
                if (!result.Succeeded)
                {
                    //If an XML modification fails, return a failure for the BSP
                    return(result);
                }
            }
            return(BootstrappingResult.Success());
        }
        /// <summary>
        /// The bootstrap.
        /// </summary>
        /// <param name="bootstrappingRequest">
        /// The bootstrapping bootstrappingRequest.
        /// </param>
        /// <returns>
        /// The <see cref="BootstrappingResult"/>.
        /// </returns>
        public override BootstrappingResult Bootstrap(BootstrappingRequest bootstrappingRequest)
        {
            IWorkloadInspector inspector;

            foreach (var configFileProperty in
                    bootstrappingRequest.Properties.Where(cp => cp.Name.Equals("log4net.ConfigurationFilePath")))
            {
                if (!this._allowComponentTypes.Contains(bootstrappingRequest.ComponentType))
                {
                    return
                        BootstrappingResult.Failure(
                            new[]
                                {
                                    "Cannot apply explicit log4net configuration to component type "
                                    + bootstrappingRequest.ComponentType + "."
                                });
                }
                if (!configFileProperty.Values.Any())
                {
                    continue;
                }

                var results =
                    configFileProperty.Values.SelectMany(p => new Log4NetConfigurationUpdateService(p).Update())
                        .ToArray();
                return results.Any() ? BootstrappingResult.Failure(results) : BootstrappingResult.Success();
            }

            switch (bootstrappingRequest.ComponentType)
            {
                case ComponentType.PublicAspNet:
                case ComponentType.AspNet:
                    inspector = new UserInterfaceWorkloadInspector(bootstrappingRequest);
                    break;
                case ComponentType.WcfService:
                    inspector = new WcfServiceWorkloadInspector(bootstrappingRequest);
                    break;
                default:
                    inspector = new IgnoredWorkloadInspector();
                    break;
            }

            return inspector.Execute();
        }
Example #5
0
        /// <summary>
        /// Find all the files ending in *.config and modify them to add the AppDynamics specific XML elements
        /// Imagine in the future we can use a Custom Property to instruct us which specific .config files to instrument
        ///
        /// Also, copy the AppD.config file with the subscription ID in the root folder of the application
        /// </summary>
        /// <param name="appName">The name of the application. This name will show up in the AppDynamics monitoring dashboard. The developer specifies this name in the Apprenda Custom Properties for her application</param>
        private static BootstrappingResult ModifyConfigFiles(BootstrappingRequest bootstrappingRequest, string appName)
        {
            string[] configFiles = Directory.GetFiles(bootstrappingRequest.ComponentPath, "web.config", SearchOption.AllDirectories);
            if (configFiles.Length <= 0)
            {
                return(BootstrappingResult.Failure(new[] { "Failed to find a web.config for application " + appName }));
            }

            foreach (string file in configFiles)
            {
                var result = ModifyXML(bootstrappingRequest, file, appName);
                if (!result.Succeeded)
                {
                    return(result);
                }
            }

            var srcHttpModuleFilePath = Path.Combine(bootstrappingRequest.BootstrapperPath, @"AppDynamicsHttpModule.dll");
            var destinationBasePath   = bootstrappingRequest.ComponentPath;

            // if this is a UI, the componentpath will not take you into the root folder of the IIS application. so we need to append it
            destinationBasePath = Path.Combine(destinationBasePath, bootstrappingRequest.ComponentName);

            var dstHttpModuleFilePath = Path.Combine(destinationBasePath, @"bin");

            dstHttpModuleFilePath = Path.Combine(dstHttpModuleFilePath, @"AppDynamicsHttpModule.dll");
            File.Copy(srcHttpModuleFilePath, dstHttpModuleFilePath, true);

            // now copy the config file that has the application name and tier name in there
            // and then open the files and replace the right values in there
            var dstConfigFilePath = Path.Combine(destinationBasePath, @"AppDynamics.config");

            File.Copy(Path.Combine(bootstrappingRequest.BootstrapperPath, @"AppDynamics.config"), dstConfigFilePath, true);

            File.WriteAllText(dstConfigFilePath, Regex.Replace(File.ReadAllText(dstConfigFilePath), "##APPLICATION_NAME##", appName));
            File.WriteAllText(dstConfigFilePath, Regex.Replace(File.ReadAllText(dstConfigFilePath), "##APPLICATION_TIER_NAME##", "Web Sites"));

            return(BootstrappingResult.Success());
        }
Example #6
0
        /// <summary>
        /// If a Custom Property "APM Application Name" exists, open up the application and add the AppDynamics
        /// specific configuration inside its *.config files
        /// </summary>
        public override BootstrappingResult Bootstrap(BootstrappingRequest bootstrappingRequest)
        {
            // if the app is a web application hosted in IIS, we need to drop the AppDynamics HTTP Module in the folder and modify the web.config
            if (bootstrappingRequest.ComponentType == ComponentType.PublicAspNet || bootstrappingRequest.ComponentType == ComponentType.AspNet)
            {
                // to get here, it means that the bootstrap policy matched the requirements of an application and we need to
                // make some changes to it based on its custom properties
                try
                {
                    var appName = bootstrappingRequest.ApplicationAlias; // use the ApplicationAlias as a default
                    foreach (CustomProperty property in bootstrappingRequest.Properties)
                    {
                        // only save the first property value in case any of these properties are multi-value custom properties
                        if (property.Name == "APM Application Name")
                        {
                            foreach (var value in property.Values)
                            {
                                appName = value;
                                if (string.IsNullOrWhiteSpace(appName))
                                {
                                    return(BootstrappingResult.Failure(new[] { "The Application Name specified for this application is invalid" }));
                                }
                                break;
                            }
                        }
                    }

                    var modifyResult = ModifyConfigFiles(bootstrappingRequest, appName);
                    return(!modifyResult.Succeeded ? modifyResult : BootstrappingResult.Success());
                }
                catch (Exception e)
                {
                    return(BootstrappingResult.Failure(new[] { e.Message }));
                }
            }
            return(BootstrappingResult.Success());
        }
        /// <summary>
        /// If a Custom Property "APM Application Name" exists, open up the application and add the AppDynamics
        /// specific configuration inside its *.config files
        /// </summary>
        public override BootstrappingResult Bootstrap(BootstrappingRequest bootstrappingRequest)
        {
            // if the app is a web application hosted in IIS, we need to drop the AppDynamics HTTP Module in the folder and modify the web.config
            if (bootstrappingRequest.ComponentType == ComponentType.PublicAspNet || bootstrappingRequest.ComponentType == ComponentType.AspNet)
            {
                // to get here, it means that the bootstrap policy matched the requirements of an application and we need to
                // make some changes to it based on its custom properties
                try
                {
                    var appName = bootstrappingRequest.ApplicationAlias; // use the ApplicationAlias as a default
                    foreach (CustomProperty property in bootstrappingRequest.Properties)
                    {
                        // only save the first property value in case any of these properties are multi-value custom properties
                        if (property.Name == "APM Application Name")
                        {
                            foreach (var value in property.Values)
                            {
                                appName = value;
                                if (string.IsNullOrWhiteSpace(appName))
                                {
                                    return BootstrappingResult.Failure(new[] { "The Application Name specified for this application is invalid" });
                                }
                                break;
                            }
                        }
                    }

                    var modifyResult = ModifyConfigFiles(bootstrappingRequest, appName);
                    return !modifyResult.Succeeded ? modifyResult : BootstrappingResult.Success();
                }
                catch (Exception e)
                {
                    return BootstrappingResult.Failure(new[] { e.Message });
                }
            }
            return BootstrappingResult.Success();
        }
Example #8
0
        private static void AddEnvVariables(ref List <object> env, BootstrappingRequest request)
        {
            string appname = string.Empty;
            string apptier = string.Empty;
            string url     = string.Empty;
            string account = string.Empty;
            string key     = string.Empty;

            //AppD Controller URL
            try
            {
                url = request.Properties.First(p => p.Name == CustomProperties.AppdController).Values.First();
                env.Add(BuildEnvVar(AppDVariables.AppdController, url));
            }
            catch (Exception ex)
            {
                throw new Exception("AppD Controller URL is not configured. Contact Platform Operator", ex);
            }


            //AppD Account
            try
            {
                account = request.Properties.First(p => p.Name == CustomProperties.AppdAccount).Values.First();
                env.Add(BuildEnvVar(AppDVariables.AppdAccount, account));
            }
            catch (Exception ex)
            {
                throw new Exception("AppD Account is not configured. Contact Platform Operator", ex);
            }

            //AppD Account Key
            try
            {
                key = request.Properties.First(p => p.Name == CustomProperties.AppdKey).Values.First();
                env.Add(BuildEnvVar(AppDVariables.AppdKey, key));
            }
            catch (Exception ex)
            {
                throw new Exception("AppD Account Key is not configured. Contact Platform Operator", ex);
            }

            //App Tier.
            try
            {
                apptier = request.Properties.First(p => p.Name == CustomProperties.AppdAppTier).Values.First();
                env.Add(BuildEnvVar(AppDVariables.AppdAppTier, apptier));
            }
            catch (Exception ex)
            {
                throw new Exception("AppD App Tier is not configured. Contact Platform Operator", ex);
            }


            //Optional App Name. If not set, derived from the App Alias
            try
            {
                appname = request.Properties.First(p => p.Name == CustomProperties.AppdAppName).Values.First();
            }
            catch (Exception)
            {
            }
            if (string.IsNullOrEmpty(appname))
            {
                appname = request.ApplicationAlias.ToUpper();
            }
            env.Add(BuildEnvVar(AppDVariables.AppdAppName, appname));
        }
Example #9
0
        public override BootstrappingResult Bootstrap(BootstrappingRequest request)
        {
            try
            {
                log.Info("AppD Bootstrapper starting");

                var requestAPM = request.Properties.First(p => p.Name == CustomProperties.APMEnable).Values.First();

                if (requestAPM != "Yes")
                {
                    log.Info("AppD instrumentation not requested");
                    return(BootstrappingResult.Success());
                }

                var yamlFilePaths = Directory.EnumerateFiles(request.ComponentPath, "*.yml")
                                    .Concat(Directory.EnumerateFiles(request.ComponentPath, "*.yaml"));

                foreach (var yamlFilePath in yamlFilePaths)
                {
                    var obj        = ReadYaml(yamlFilePath);
                    var spec       = GetOrCreateYamlNode(obj, "spec");
                    var template   = GetOrCreateYamlNode(spec, "template");
                    var contSpec   = GetOrCreateYamlNode(template, "spec");
                    var containers = GetOrCreateYamlNodeList(contSpec, "containers");

                    int i = 0;
                    foreach (var c in containers)
                    {
                        if (i == 0)
                        {
                            var env = GetOrCreateYamlNodeList(((Dictionary <object, object>)c), "env");
                            AddEnvVariables(ref env, request);
                            break;
                        }
                    }

                    WriteYaml(yamlFilePath, obj);
                }

                log.Info("AppD instrumentation is complete");

                //var jsonFilePaths = Directory.EnumerateFiles(request.ComponentPath, "*.json");

                //foreach (var jsonFilePath in jsonFilePaths)
                //{
                //    var obj = (JObject)JsonConvert.DeserializeObject(File.ReadAllText(jsonFilePath));
                //    var spec = GetOrCreateJsonNode(obj, "spec");
                //    var template = GetOrCreateJsonNode(spec, "template");
                //    var contSpec = GetOrCreateJsonNode(template, "spec");
                //    var containers = GetOrCreateJsonNode(contSpec, "containers");


                //    File.WriteAllText(jsonFilePath, JsonConvert.SerializeObject(obj, Formatting.Indented));
                //}
            }
            catch (Exception ex)
            {
                log.Error("Error instrumenting perf monitoring for the app" + ex.Message);
                return(BootstrappingResult.Failure(new[] { $"Error instrumenting perf monitoring for the app. {ex}" }));
            }

            return(BootstrappingResult.Success());
        }
Example #10
0
        public override BootstrappingResult Bootstrap(BootstrappingRequest request)
        {
            try
            {
                log.Info("DBClone Bootstrapper starting");

                var prop = request.Properties.First(p => p.Name == CustomProperties.DBCloneType);
                if (prop == null || prop.Values == null || string.IsNullOrEmpty(prop.Values.First()) || prop.Values.First().ToLower() == "none")
                {
                    log.Info("DB Cloning not requested");
                    return(BootstrappingResult.Success());
                }

                var propDBServer = request.Properties.First(p => p.Name == CustomProperties.SnapDBCloneHost);
                if (propDBServer == null || propDBServer.Values == null || string.IsNullOrEmpty(propDBServer.Values.First()))
                {
                    log.Error($"Cloning requested but the DB host name is missing. Configure the host name or do not request connection to the cloned DB by setting DBCloneType property to 'none'");
                    return(BootstrappingResult.Failure(new[] { $"Cloning requested but the DB host name is missing" }));
                }
                string serverName = propDBServer.Values.First();

                var propDBName = request.Properties.First(p => p.Name == CustomProperties.SnapDBName);
                if (propDBName == null || propDBName.Values == null || string.IsNullOrEmpty(propDBName.Values.First()))
                {
                    log.Error($"Cloning requested but the cloned DB name is missing. Configure the DB name or do not request connection to the cloned DB by setting DBCloneType property to 'none'");
                    return(BootstrappingResult.Failure(new[] { $"Cloning requested but the cloned DB name is missing." }));
                }
                string dbName = propDBName.Values.First();

                var propDBUser = request.Properties.First(p => p.Name == CustomProperties.DBUser);
                if (propDBUser == null || propDBUser.Values == null || string.IsNullOrEmpty(propDBUser.Values.First()))
                {
                    log.Error($"Cloning requested but the DB user is not configured. Configure the DB user or do not request connection to the cloned DB by setting DBCloneType property to 'none'");
                    return(BootstrappingResult.Failure(new[] { $"Cloning requested but the DB user is not configured." }));
                }
                string dbUser = propDBUser.Values.First();

                var propDBUserPass = request.Properties.First(p => p.Name == CustomProperties.DBUserCreds);
                if (propDBUserPass == null || propDBUserPass.Values == null || string.IsNullOrEmpty(propDBUserPass.Values.First()))
                {
                    log.Error($"Cloning requested but the DB user password is not set. Configure the DB user password or do not request connection to the cloned DB by setting DBCloneType property to 'none'");
                    return(BootstrappingResult.Failure(new[] { $"Cloning requested but the DB user is not configured." }));
                }
                string dbUserPass = propDBUserPass.Values.First();
                log.Info($"Retrieving web config for modification from path {request.ComponentPath}");
                string[] configFiles = Directory.GetFiles(request.ComponentPath, "Web.config", SearchOption.AllDirectories);
                if (configFiles.Length <= 0)
                {
                    log.Error($"Config file not found in  {request.ComponentPath}");
                    return(BootstrappingResult.Failure(new[] { "Failed to find a web.config for application " + request.ApplicationAlias }));
                }

                string filePath = configFiles[0];
                //string cloneDB = SnapSession.BuildCloneName(dbName, request.ApplicationAlias);
                UpdateConnectionString(filePath, serverName, dbUser, dbName, dbUserPass);

                log.Info("Connection string mod for MySql is complete");
            }
            catch (Exception ex)
            {
                log.Error($"Error updating connection info for application {request.ApplicationAlias}. Reason: {ex.Message}");
                return(BootstrappingResult.Failure(new[] { $"Error updating connection info for application {request.ApplicationAlias}. Reason: {ex.Message}" }));
            }

            return(BootstrappingResult.Success());
        }
Example #11
0
        private static BootstrappingResult ModifyXML(BootstrappingRequest bootstrappingRequest, string filePath)
        {
            try
            {
                /*By default, IIS adds the negotiate and NTLM providers as part of windows authentication.
                 * If you need those sections to explictely be added, uncomment the following section.
                 * */

                //Traverse the web.config file and find the required section
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(filePath);

                //Find the System.webserver section
                XmlNode systemWebServer = xmlDoc.SelectSingleNode("//system.webServer");

                //Create the necessary sections
                XmlNode security                = xmlDoc.CreateNode(XmlNodeType.Element, "security", null);
                XmlNode authentication          = xmlDoc.CreateNode(XmlNodeType.Element, "authentication", null);
                XmlNode anonymousAuthentication = xmlDoc.CreateNode(XmlNodeType.Element, "anonymousAuthentication", null);
                XmlNode windowsAuthentication   = xmlDoc.CreateNode(XmlNodeType.Element, "windowsAuthentication", null);

                /* Providers, uncomment if needed
                 * XmlNode providers = xmlDoc.CreateNode(XmlNodeType.Element, "providers", null);
                 * XmlNode ntlmProvider = xmlDoc.CreateNode(XmlNodeType.Element, "add", null);
                 * */

                //Create the necessary attributes for windows and anonymous authentication
                XmlAttribute anonymousAuthenticationEnabled = xmlDoc.CreateAttribute("enabled");
                XmlAttribute windowsAuthenticationEnabled   = xmlDoc.CreateAttribute("enabled");
                anonymousAuthenticationEnabled.Value = "false";
                windowsAuthenticationEnabled.Value   = "true";

                /* Providers, uncomment if needed
                 * XmlAttribute ntlmAuth = xmlDoc.CreateAttribute("value");
                 * ntlmAuth.Value = "NTLM";
                 * */

                //Create the tree by appending all elements, children and nodes
                //ntlmProvider.Attributes.Append(ntlmAuth);
                anonymousAuthentication.Attributes.Append(anonymousAuthenticationEnabled);
                windowsAuthentication.Attributes.Append(windowsAuthenticationEnabled);
                //providers.AppendChild(ntlmProvider);
                //windowsAuthentication.AppendChild(providers);
                authentication.AppendChild(anonymousAuthentication);
                authentication.AppendChild(windowsAuthentication);
                security.AppendChild(authentication);

                //If there is no Windows Authentication, add the section
                if (null == systemWebServer)
                {
                    systemWebServer = xmlDoc.CreateNode(XmlNodeType.Element, "system.webServer", null);
                    systemWebServer.AppendChild(security);

                    XmlNode configuration = xmlDoc.SelectSingleNode("//configuration");
                    configuration.AppendChild(systemWebServer);
                    xmlDoc.Save(filePath);
                    return(BootstrappingResult.Success());
                }
                //If System.webserver is found, append the security section
                else if (null != systemWebServer)
                {
                    systemWebServer.AppendChild(security);
                    xmlDoc.Save(filePath);
                    return(BootstrappingResult.Success());
                }
                return(BootstrappingResult.Success());
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    return(BootstrappingResult.Failure(new[] { ex.InnerException.Message }));
                }
                else
                {
                    return(BootstrappingResult.Failure(new[] { ex.Message }));
                }
            }
        }
Example #12
0
        /// <summary>
        /// Edit the specified .config file and add the AppDynamics xml elements
        /// Assumes the AppDynamics agent is installed on all the Apprenda nodes and it is set to instrument all applications (IIS-based and non-IIS-based)
        /// Assumes the AppD.config contains at least the following content to instrument the WCF container for Apprenda apps:
        ///     <instrumentation>
        ///         <applications>
        ///             <application name="Apprenda.WCFServiceHost.exe" />
        ///         </applications>
        ///     </instrumentation>
        /// </summary>
        private static BootstrappingResult ModifyXML(BootstrappingRequest bootstrappingRequest, string filePath, string appName)
        {
            // because we need to work with any *.config files, we can't use the webconfigurationmanager class
            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.Load(filePath);

            /*
             * XmlNode appsettingsNode = xmlDoc.SelectSingleNode("//appSettings");
             * if (null == appsettingsNode)
             * {
             *  // we didn't find an appSettings Node - creating it
             *  xmlDoc.AppendChild(CreateNewNode("appSettings", xmlDoc));
             *  appsettingsNode = xmlDoc.SelectSingleNode("//appSettings");
             * }
             */

            XmlElement httpModuleElement = (XmlElement)xmlDoc.SelectSingleNode("//system.webServer/modules/add[@name = 'AppDynamicsHttpModule']");

            if (null == httpModuleElement)
            {
                XmlNode webServerNode = xmlDoc.SelectSingleNode("//system.webServer");
                if (null == webServerNode)
                {
                    xmlDoc.AppendChild(CreateNewNode("system.webServer", xmlDoc));
                    webServerNode = xmlDoc.SelectSingleNode("//system.webServer");
                }
                XmlNode modulesNode = xmlDoc.SelectSingleNode("//system.webServer/modules");
                if (null == modulesNode)
                {
                    webServerNode.AppendChild(CreateNewNode("modules", xmlDoc));
                    modulesNode = xmlDoc.SelectSingleNode("//system.webServer/modules");
                }

                modulesNode.AppendChild(CreateNewElement("name", "AppDynamicsHttpModule", "type", "AppDynamics.AppDynamicsHttpModule, AppDynamicsHttpModule", xmlDoc, modulesNode));
            }
            else
            {
                // modify an existing value
                httpModuleElement.Attributes["type"].Value = "AppDynamics.AppDynamicsHttpModule, AppDynamicsHttpModule";
            }

            /*
             * XmlElement appNameElement = (XmlElement)xmlDoc.SelectSingleNode("//appSettings/add[@key = 'APPDYNAMICS_AGENT_APPLICATION_NAME']");
             * XmlElement tierNameElement = (XmlElement)xmlDoc.SelectSingleNode("//appSettings/add[@key = 'APPDYNAMICS_AGENT_TIER_NAME']");
             *
             * if (null == appNameElement)
             * {
             *  // value does not exist, let's create it
             *  appsettingsNode.AppendChild(CreateNewElement("key", "APPDYNAMICS_AGENT_APPLICATION_NAME", "value", appName, xmlDoc, appsettingsNode));
             * }
             * else
             * {
             *  // modify an existing value
             *  appNameElement.Attributes["value"].Value = appName;
             * }
             *
             * if (null == tierNameElement)
             * {
             *  // value does not exist, let's create it
             *  appsettingsNode.AppendChild(CreateNewElement("key", "APPDYNAMICS_AGENT_TIER_NAME", "value", "Web Sites", xmlDoc, appsettingsNode));
             * }
             * else
             * {
             *  // modify an existing value
             *  tierNameElement.Attributes["value"].Value = "Web Sites";
             * }
             */

            xmlDoc.Save(filePath);

            return(BootstrappingResult.Success());
        }
        /// <summary>
        /// Find all the files ending in *.config and modify them to add the AppDynamics specific XML elements
        /// Imagine in the future we can use a Custom Property to instruct us which specific .config files to instrument
        /// 
        /// Also, copy the AppD.config file with the subscription ID in the root folder of the application
        /// </summary>
        /// <param name="appName">The name of the application. This name will show up in the AppDynamics monitoring dashboard. The developer specifies this name in the Apprenda Custom Properties for her application</param>        
        private static BootstrappingResult ModifyConfigFiles(BootstrappingRequest bootstrappingRequest, string appName)
        {
            string[] configFiles = Directory.GetFiles(bootstrappingRequest.ComponentPath, "web.config", SearchOption.AllDirectories);
            if (configFiles.Length <= 0)
            {
                return BootstrappingResult.Failure(new[] { "Failed to find a web.config for application " + appName });
            }

            foreach (string file in configFiles)
            {
                var result = ModifyXML(bootstrappingRequest, file, appName);
                if (!result.Succeeded)
                {
                    return result;
                }
            }

            var srcHttpModuleFilePath = Path.Combine(bootstrappingRequest.BootstrapperPath, @"AppDynamicsHttpModule.dll");
            var destinationBasePath = bootstrappingRequest.ComponentPath;

            // if this is a UI, the componentpath will not take you into the root folder of the IIS application. so we need to append it
            destinationBasePath = Path.Combine(destinationBasePath, bootstrappingRequest.ComponentName);

            var dstHttpModuleFilePath = Path.Combine(destinationBasePath, @"bin");
            dstHttpModuleFilePath = Path.Combine(dstHttpModuleFilePath, @"AppDynamicsHttpModule.dll");
            File.Copy(srcHttpModuleFilePath, dstHttpModuleFilePath, true);

            // now copy the config file that has the application name and tier name in there
            // and then open the files and replace the right values in there
            var dstConfigFilePath = Path.Combine(destinationBasePath, @"AppDynamics.config");
            File.Copy(Path.Combine(bootstrappingRequest.BootstrapperPath, @"AppDynamics.config"), dstConfigFilePath, true);

            File.WriteAllText(dstConfigFilePath, Regex.Replace(File.ReadAllText(dstConfigFilePath), "##APPLICATION_NAME##", appName));
            File.WriteAllText(dstConfigFilePath, Regex.Replace(File.ReadAllText(dstConfigFilePath), "##APPLICATION_TIER_NAME##", "Web Sites"));

            return BootstrappingResult.Success();
        }
        /// <summary>
        /// Edit the specified .config file and add the AppDynamics xml elements
        /// Assumes the AppDynamics agent is installed on all the Apprenda nodes and it is set to instrument all applications (IIS-based and non-IIS-based)
        /// Assumes the AppD.config contains at least the following content to instrument the WCF container for Apprenda apps:
        ///     <instrumentation>
        ///         <applications>
        ///             <application name="Apprenda.WCFServiceHost.exe" />
        ///         </applications>
        ///     </instrumentation>
        /// </summary>
        private static BootstrappingResult ModifyXML(BootstrappingRequest bootstrappingRequest, string filePath, string appName)
        {
            // because we need to work with any *.config files, we can't use the webconfigurationmanager class
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filePath);

            /*
            XmlNode appsettingsNode = xmlDoc.SelectSingleNode("//appSettings");
            if (null == appsettingsNode)
            {
                // we didn't find an appSettings Node - creating it
                xmlDoc.AppendChild(CreateNewNode("appSettings", xmlDoc));
                appsettingsNode = xmlDoc.SelectSingleNode("//appSettings");
            }
            */

            XmlElement httpModuleElement = (XmlElement)xmlDoc.SelectSingleNode("//system.webServer/modules/add[@name = 'AppDynamicsHttpModule']");
            if (null == httpModuleElement)
            {
                XmlNode webServerNode = xmlDoc.SelectSingleNode("//system.webServer");
                if (null == webServerNode)
                {
                    xmlDoc.AppendChild(CreateNewNode("system.webServer", xmlDoc));
                    webServerNode = xmlDoc.SelectSingleNode("//system.webServer");
                }
                XmlNode modulesNode = xmlDoc.SelectSingleNode("//system.webServer/modules");
                if (null == modulesNode)
                {
                    webServerNode.AppendChild(CreateNewNode("modules", xmlDoc));
                    modulesNode = xmlDoc.SelectSingleNode("//system.webServer/modules");
                }

                modulesNode.AppendChild(CreateNewElement("name", "AppDynamicsHttpModule", "type", "AppDynamics.AppDynamicsHttpModule, AppDynamicsHttpModule", xmlDoc, modulesNode));
            }
            else
            {
                // modify an existing value
                httpModuleElement.Attributes["type"].Value = "AppDynamics.AppDynamicsHttpModule, AppDynamicsHttpModule";
            }

            /*
            XmlElement appNameElement = (XmlElement)xmlDoc.SelectSingleNode("//appSettings/add[@key = 'APPDYNAMICS_AGENT_APPLICATION_NAME']");
            XmlElement tierNameElement = (XmlElement)xmlDoc.SelectSingleNode("//appSettings/add[@key = 'APPDYNAMICS_AGENT_TIER_NAME']");

            if (null == appNameElement)
            {
                // value does not exist, let's create it
                appsettingsNode.AppendChild(CreateNewElement("key", "APPDYNAMICS_AGENT_APPLICATION_NAME", "value", appName, xmlDoc, appsettingsNode));
            }
            else
            {
                // modify an existing value
                appNameElement.Attributes["value"].Value = appName;
            }

            if (null == tierNameElement)
            {
                // value does not exist, let's create it
                appsettingsNode.AppendChild(CreateNewElement("key", "APPDYNAMICS_AGENT_TIER_NAME", "value", "Web Sites", xmlDoc, appsettingsNode));
            }
            else
            {
                // modify an existing value
                tierNameElement.Attributes["value"].Value = "Web Sites";
            }
            */

            xmlDoc.Save(filePath);

            return BootstrappingResult.Success();
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="WcfServiceWorkloadInspector"/> class.
 /// </summary>
 /// <param name="request">
 /// The request.
 /// </param>
 public WcfServiceWorkloadInspector(BootstrappingRequest request)
 {
     this._request = request;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="UserInterfaceWorkloadInspector"/> class.
 /// </summary>
 /// <param name="request">
 /// The request.
 /// </param>
 public UserInterfaceWorkloadInspector(BootstrappingRequest request)
 {
     this._request = request;
 }