Exemplo n.º 1
0
 // <summary>
 // Returns a lambda function that checks if an incoming request object's url path
 // is prepended by a string
 // </summary>
 // <param name="relativeUrl">
 // String keyword with which incoming request's path is matched
 // </param>
 // <param name="httpContext">
 // The HttpContext object of an incoming request
 // </param>
 private void OnShutdown()
 {
     KuduWebUtil.TraceShutdown(_webAppRuntimeEnvironment, _noContextDeploymentsSettingsManager);
     // Cleaning up deployment locks
     Console.WriteLine(@"Removing Deployment Locks");
     FileSystemHelpers.DeleteDirectorySafe("/home/site/locks/deployment");
     Console.WriteLine(@"Shutting Down!");
 }
Exemplo n.º 2
0
 internal static void AddDeploymentServices(this IServiceCollection services, IEnvironment environment)
 {
     services.AddScoped <ISettings>(sp => new XmlSettings.Settings(KuduWebUtil.GetSettingsPath(environment)));
     services.AddScoped <IDeploymentSettingsManager, DeploymentSettingsManager>();
     services.AddScoped <IDeploymentStatusManager, DeploymentStatusManager>();
     services.AddScoped <ISiteBuilderFactory, SiteBuilderFactory>();
     services.AddScoped <IWebHooksManager, WebHooksManager>();
 }
Exemplo n.º 3
0
        internal static void AddLogStreamService(this IServiceCollection services,
                                                 IEnvironment environment,
                                                 ITraceFactory traceFactory)
        {
            var logStreamManagerLock = KuduWebUtil.GetNamedLocks(traceFactory, environment)["hooks"];

            services.AddTransient(sp => new LogStreamManager(Path.Combine(environment.RootPath, Constants.LogFilesPath),
                                                             sp.GetRequiredService <IEnvironment>(),
                                                             sp.GetRequiredService <IDeploymentSettingsManager>(),
                                                             sp.GetRequiredService <ITracer>(),
                                                             logStreamManagerLock));
        }
Exemplo n.º 4
0
 internal static void AddGitServer(this IServiceCollection services, IOperationLock deploymentLock)
 {
     services.AddTransient <IDeploymentEnvironment, DeploymentEnvironment>();
     services.AddScoped <IGitServer>(sp =>
                                     new GitExeServer(
                                         sp.GetRequiredService <IEnvironment>(),
                                         deploymentLock,
                                         KuduWebUtil.GetRequestTraceFile(sp),
                                         sp.GetRequiredService <IRepositoryFactory>(),
                                         sp.GetRequiredService <IDeploymentEnvironment>(),
                                         sp.GetRequiredService <IDeploymentSettingsManager>(),
                                         sp.GetRequiredService <ITraceFactory>()));
 }
Exemplo n.º 5
0
        /// <summary>
        /// This method gets called by the runtime. It is used to add services
        /// to the container. It uses the Extension pattern.
        /// </summary>
        /// <todo>
        ///   CORE TODO Remove initializing contextAccessor : See if over time we can refactor away the need for this?
        ///   It's kind of a quick hack/compatibility shim. Ideally you want to get the request context only from where
        ///   it's specifically provided to you (Request.HttpContext in a controller, or as an Invoke() parameter in
        ///   a middleware) and pass it wherever its needed.
        /// </todo>
        public void ConfigureServices(IServiceCollection services)
        {
            Console.WriteLine(@"Configure Services : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));

            services.Configure <FormOptions>(options =>
            {
                options.MultipartBodyLengthLimit = 52428800;
                options.ValueCountLimit          = 500000;
                options.KeyLengthLimit           = 500000;
            });

            services.AddRouteAnalyzer();

            // Kudu.Services contains all the Controllers
            var kuduServicesAssembly = Assembly.Load("Kudu.Services");

            services.AddMvcCore()
            .AddRazorPages()
            .AddAuthorization()
            .AddJsonFormatters()
            .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver())
            .AddApplicationPart(kuduServicesAssembly).AddControllersAsServices()
            .AddApiExplorer();


            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info {
                    Title = "Kudu API Docs"
                });
                // Setting the comments path for the Swagger JSON and UI.
                var xmlFile = $"Kudu.Services.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            });

            services.AddGZipCompression();

            services.AddDirectoryBrowser();

            services.AddDataProtection();

            services.AddLogging(
                builder =>
            {
                builder.AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddConsole();
            });

            services.AddSingleton <IHttpContextAccessor>(new HttpContextAccessor());

            KuduWebUtil.EnsureHomeEnvironmentVariable();

            KuduWebUtil.EnsureSiteBitnessEnvironmentVariable();

            IEnvironment environment = KuduWebUtil.GetEnvironment(_hostingEnvironment);

            _webAppRuntimeEnvironment = environment;

            KuduWebUtil.EnsureDotNetCoreEnvironmentVariable(environment);

            // CORE TODO Check this
            // fix up invalid /home/site/deployments/settings.xml
            KuduWebUtil.EnsureValidDeploymentXmlSettings(environment);

            // Add various folders that never change to the process path. All child processes will inherit this
            KuduWebUtil.PrependFoldersToPath(environment);

            // General
            services.AddSingleton <IServerConfiguration>(ServerConfiguration);

            // CORE TODO Looks like this doesn't ever actually do anything, can refactor out?
            services.AddSingleton <IBuildPropertyProvider>(new BuildPropertyProvider());

            _noContextDeploymentsSettingsManager =
                new DeploymentSettingsManager(new XmlSettings.Settings(KuduWebUtil.GetSettingsPath(environment)));
            TraceServices.TraceLevel = _noContextDeploymentsSettingsManager.GetTraceLevel();

            // Per request environment
            services.AddScoped(sp =>
                               KuduWebUtil.GetEnvironment(_hostingEnvironment, sp.GetRequiredService <IDeploymentSettingsManager>()));

            services.AddDeploymentServices(environment);

            /*
             * CORE TODO Refactor ITracerFactory/ITracer/GetTracer()/
             * ILogger needs serious refactoring:
             * - Names should be changed to make it clearer that ILogger is for deployment
             *   logging and ITracer and friends are for Kudu tracing
             * - ILogger is a first-class citizen in .NET core and has it's own meaning. We should be using it
             *   where appropriate (and not name-colliding with it)
             * - ITracer vs. ITraceFactory is redundant and confusing.
             * - TraceServices only serves to confuse stuff now that we're avoiding
             */
            Func <IServiceProvider, ITracer> resolveTracer = KuduWebUtil.GetTracer;

            ITracer CreateTracerThunk() => resolveTracer(services.BuildServiceProvider());

            // First try to use the current request profiler if any, otherwise create a new one
            var traceFactory = new TracerFactory(() =>
            {
                var sp      = services.BuildServiceProvider();
                var context = sp.GetRequiredService <IHttpContextAccessor>().HttpContext;
                return(TraceServices.GetRequestTracer(context) ?? resolveTracer(sp));
            });

            services.AddScoped <ITracer>(sp =>
            {
                var context = sp.GetRequiredService <IHttpContextAccessor>().HttpContext;
                return(TraceServices.GetRequestTracer(context) ?? NullTracer.Instance);
            });

            services.AddSingleton <ITraceFactory>(traceFactory);

            TraceServices.SetTraceFactory(CreateTracerThunk);

            services.AddSingleton <IDictionary <string, IOperationLock> >(
                KuduWebUtil.GetNamedLocks(traceFactory, environment));

            // CORE TODO ShutdownDetector, used by LogStreamManager.
            //var shutdownDetector = new ShutdownDetector();
            //shutdownDetector.Initialize()

            var noContextTraceFactory = new TracerFactory(() =>
                                                          KuduWebUtil.GetTracerWithoutContext(environment, _noContextDeploymentsSettingsManager));

            services.AddTransient <IAnalytics>(sp => new Analytics(sp.GetRequiredService <IDeploymentSettingsManager>(),
                                                                   sp.GetRequiredService <IServerConfiguration>(),
                                                                   noContextTraceFactory));

            // CORE TODO
            // Trace shutdown event
            // Cannot use shutdownDetector.Token.Register because of race condition
            // with NinjectServices.Stop via WebActivator.ApplicationShutdownMethodAttribute
            // Shutdown += () => TraceShutdown(environment, noContextDeploymentsSettingsManager);

            // LogStream service
            services.AddLogStreamService(_webAppRuntimeEnvironment, traceFactory);

            // Deployment Service
            services.AddWebJobsDependencies();

            services.AddScoped <ILogger>(KuduWebUtil.GetDeploymentLogger);

            services.AddScoped <IDeploymentManager, DeploymentManager>();

            services.AddScoped <IFetchDeploymentManager, FetchDeploymentManager>();

            services.AddScoped <ISSHKeyManager, SSHKeyManager>();

            services.AddScoped <IRepositoryFactory>(
                sp => KuduWebUtil.GetDeploymentLock(traceFactory, environment).RepositoryFactory =
                    new RepositoryFactory(
                        sp.GetRequiredService <IEnvironment>(), sp.GetRequiredService <IDeploymentSettingsManager>(),
                        sp.GetRequiredService <ITraceFactory>()));

            services.AddScoped <IApplicationLogsReader, ApplicationLogsReader>();

            // Git server
            services.AddGitServer(KuduWebUtil.GetDeploymentLock(traceFactory, environment));

            // Git Servicehook Parsers
            services.AddGitServiceHookParsers();

            services.AddScoped <ICommandExecutor, CommandExecutor>();

            // KuduWebUtil.MigrateSite(environment, noContextDeploymentsSettingsManager);
            // RemoveOldTracePath(environment);
            // RemoveTempFileFromUserDrive(environment);

            // CORE TODO Windows Fix: Temporary fix for https://github.com/npm/npm/issues/5905
            //EnsureNpmGlobalDirectory();
            //EnsureUserProfileDirectory();

            //// Skip SSL Certificate Validate
            //if (Environment.SkipSslValidation)
            //{
            //    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            //}

            //// Make sure webpages:Enabled is true. Even though we set it in web.config, it could be overwritten by
            //// an Azure AppSetting that's supposed to be for the site only but incidently affects Kudu as well.
            ConfigurationManager.AppSettings["webpages:Enabled"] = "true";

            //// Kudu does not rely owin:appStartup.  This is to avoid Azure AppSetting if set.
            if (ConfigurationManager.AppSettings?["owin:appStartup"] != null)
            {
                // Set the appSetting to null since we cannot use AppSettings.Remove(key) (ReadOnly exception!)
                ConfigurationManager.AppSettings["owin:appStartup"] = null;
            }

            //RegisterRoutes(kernel, RouteTable.Routes);

            //// Register the default hubs route: ~/signalr
            //GlobalHost.DependencyResolver = new SignalRNinjectDependencyResolver(kernel);
            //GlobalConfiguration.Configuration.Filters.Add(
            //    new TraceDeprecatedActionAttribute(
            //        kernel.Get<IAnalytics>(),
            //        kernel.Get<ITraceFactory>()));
            //GlobalConfiguration.Configuration.Filters.Add(new EnsureRequestIdHandlerAttribute());

            //FileTarget target = LogManager.Configuration.FindTargetByName("file") as FileTarget;
            //String logfile = _webAppRuntimeEnvironment.LogFilesPath + "/.txt";
            //target.FileName = logfile;
        }
Exemplo n.º 6
0
        public void Configure(IApplicationBuilder app,
                              IApplicationLifetime applicationLifetime,
                              ILoggerFactory loggerFactory)
        {
            Console.WriteLine(@"Configure : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));

            loggerFactory.AddEventSourceLogger();

            KuduWebUtil.MigrateToNetCorePatch(_webAppRuntimeEnvironment);

            if (_hostingEnvironment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }


            var webSocketOptions = new WebSocketOptions()
            {
                KeepAliveInterval = TimeSpan.FromSeconds(15)
            };

            app.UseWebSockets(webSocketOptions);

            var containsRelativePath = new Func <HttpContext, bool>(i =>
                                                                    i.Request.Path.Value.StartsWith("/Default", StringComparison.OrdinalIgnoreCase));

            app.MapWhen(containsRelativePath, application => application.Run(async context =>
            {
                await context.Response.WriteAsync("Kestrel Running");
            }));

            var containsRelativePath2 = new Func <HttpContext, bool>(i =>
                                                                     i.Request.Path.Value.StartsWith("/info", StringComparison.OrdinalIgnoreCase));

            app.MapWhen(containsRelativePath2,
                        application => application.Run(async context =>
            {
                await context.Response.WriteAsync("{\"Version\":\"" + Constants.KuduBuild + "\"}");
            }));

            app.UseResponseCompression();

            var containsRelativePath3 = new Func <HttpContext, bool>(i =>
                                                                     i.Request.Path.Value.StartsWith("/AppServiceTunnel/Tunnel.ashx", StringComparison.OrdinalIgnoreCase));

            app.MapWhen(containsRelativePath3, builder => builder.UseMiddleware <DebugExtensionMiddleware>());

            app.UseTraceMiddleware();

            applicationLifetime.ApplicationStopping.Register(OnShutdown);

            app.UseStaticFiles();

            ProxyRequestIfRelativeUrlMatches(@"/webssh", "http", "127.0.0.1", "3000", app);

            var configuration = app.ApplicationServices.GetRequiredService <IServerConfiguration>();

            // CORE TODO any equivalent for this? Needed?
            //var configuration = kernel.Get<IServerConfiguration>();
            //GlobalConfiguration.Configuration.Formatters.Clear();
            //GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

            var jsonFormatter = new JsonMediaTypeFormatter();


            // CORE TODO concept of "deprecation" in routes for traces, Do we need this for linux ?

            // Push url
            foreach (var url in new[] { "/git-receive-pack", $"/{configuration.GitServerRoot}/git-receive-pack" })
            {
                app.Map(url, appBranch => appBranch.RunReceivePackHandler());
            }

            // Fetch hook
            app.Map("/deploy", appBranch => appBranch.RunFetchHandler());

            // Log streaming
            app.Map("/api/logstream", appBranch => appBranch.RunLogStreamHandler());


            // Clone url
            foreach (var url in new[] { "/git-upload-pack", $"/{configuration.GitServerRoot}/git-upload-pack" })
            {
                app.Map(url, appBranch => appBranch.RunUploadPackHandler());
            }

            // Custom GIT repositories, which can be served from any directory that has a git repo
            foreach (var url in new[] { "/git-custom-repository", "/git/{*path}" })
            {
                app.Map(url, appBranch => appBranch.RunCustomGitRepositoryHandler());
            }

            // Sets up the file server to web app's wwwroot
            KuduWebUtil.SetupFileServer(app, _webAppRuntimeEnvironment.WebRootPath, "/wwwroot");

            // Sets up the file server to LogFiles
            KuduWebUtil.SetupFileServer(app, Path.Combine(_webAppRuntimeEnvironment.LogFilesPath, "kudu", "deployment"), "/deploymentlogs");

            app.UseSwagger();

            app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Kudu API Docs"); });

            app.UseMvc(routes =>
            {
                Console.WriteLine(@"Setting Up Routes : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));
                routes.MapRouteAnalyzer("/routes"); // Add

                routes.MapRoute(
                    name: "default",
                    template: "{controller}/{action=Index}/{id?}");

                // Git Service
                routes.MapRoute("git-info-refs-root", "info/refs", new { controller = "InfoRefs", action = "Execute" });
                routes.MapRoute("git-info-refs", configuration.GitServerRoot + "/info/refs",
                                new { controller = "InfoRefs", action = "Execute" });

                // Scm (deployment repository)
                routes.MapHttpRouteDual("scm-info", "scm/info",
                                        new { controller = "LiveScm", action = "GetRepositoryInfo" });
                routes.MapHttpRouteDual("scm-clean", "scm/clean", new { controller = "LiveScm", action = "Clean" });
                routes.MapHttpRouteDual("scm-delete", "scm", new { controller = "LiveScm", action = "Delete" },
                                        new { verb = new HttpMethodRouteConstraint("DELETE") });


                // Scm files editor
                routes.MapHttpRouteDual("scm-get-files", "scmvfs/{*path}",
                                        new { controller = "LiveScmEditor", action = "GetItem" },
                                        new { verb = new HttpMethodRouteConstraint("GET", "HEAD") });
                routes.MapHttpRouteDual("scm-put-files", "scmvfs/{*path}",
                                        new { controller = "LiveScmEditor", action = "PutItem" },
                                        new { verb = new HttpMethodRouteConstraint("PUT") });
                routes.MapHttpRouteDual("scm-delete-files", "scmvfs/{*path}",
                                        new { controller = "LiveScmEditor", action = "DeleteItem" },
                                        new { verb = new HttpMethodRouteConstraint("DELETE") });

                // Live files editor
                routes.MapHttpRouteDual("vfs-get-files", "vfs/{*path}", new { controller = "Vfs", action = "GetItem" },
                                        new { verb = new HttpMethodRouteConstraint("GET", "HEAD") });
                routes.MapHttpRouteDual("vfs-put-files", "vfs/{*path}", new { controller = "Vfs", action = "PutItem" },
                                        new { verb = new HttpMethodRouteConstraint("PUT") });
                routes.MapHttpRouteDual("vfs-delete-files", "vfs/{*path}",
                                        new { controller = "Vfs", action = "DeleteItem" },
                                        new { verb = new HttpMethodRouteConstraint("DELETE") });

                // Zip file handler
                routes.MapHttpRouteDual("zip-get-files", "zip/{*path}", new { controller = "Zip", action = "GetItem" },
                                        new { verb = new HttpMethodRouteConstraint("GET", "HEAD") });
                routes.MapHttpRouteDual("zip-put-files", "zip/{*path}", new { controller = "Zip", action = "PutItem" },
                                        new { verb = new HttpMethodRouteConstraint("PUT") });

                // Zip push deployment
                routes.MapRoute("zip-push-deploy", "api/zipdeploy",
                                new { controller = "PushDeployment", action = "ZipPushDeploy" },
                                new { verb = new HttpMethodRouteConstraint("POST") });
                routes.MapRoute("zip-war-deploy", "api/wardeploy",
                                new { controller = "PushDeployment", action = "WarPushDeploy" },
                                new { verb = new HttpMethodRouteConstraint("POST") });

                // Live Command Line
                routes.MapHttpRouteDual("execute-command", "command",
                                        new { controller = "Command", action = "ExecuteCommand" },
                                        new { verb = new HttpMethodRouteConstraint("POST") });

                // Deployments
                routes.MapHttpRouteDual("all-deployments", "deployments",
                                        new { controller = "Deployment", action = "GetDeployResults" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpRouteDual("one-deployment-get", "deployments/{id}",
                                        new { controller = "Deployment", action = "GetResult" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpRouteDual("one-deployment-put", "deployments/{id?}",
                                        new { controller = "Deployment", action = "Deploy" },
                                        new { verb = new HttpMethodRouteConstraint("PUT") });
                routes.MapHttpRouteDual("one-deployment-delete", "deployments/{id}",
                                        new { controller = "Deployment", action = "Delete" },
                                        new { verb = new HttpMethodRouteConstraint("DELETE") });
                routes.MapHttpRouteDual("one-deployment-log", "deployments/{id}/log",
                                        new { controller = "Deployment", action = "GetLogEntry" });
                routes.MapHttpRouteDual("one-deployment-log-details", "deployments/{id}/log/{logId}",
                                        new { controller = "Deployment", action = "GetLogEntryDetails" });

                // Deployment script
                routes.MapRoute("get-deployment-script", "api/deploymentscript",
                                new { controller = "Deployment", action = "GetDeploymentScript" },
                                new { verb = new HttpMethodRouteConstraint("GET") });

                // IsDeploying status
                routes.MapRoute("is-deployment-underway", "api/isdeploying",
                                new { controller = "Deployment", action = "IsDeploying" },
                                new { verb = new HttpMethodRouteConstraint("GET") });

                // SSHKey
                routes.MapHttpRouteDual("get-sshkey", "api/sshkey",
                                        new { controller = "SSHKey", action = "GetPublicKey" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpRouteDual("put-sshkey", "api/sshkey",
                                        new { controller = "SSHKey", action = "SetPrivateKey" },
                                        new { verb = new HttpMethodRouteConstraint("PUT") });
                routes.MapHttpRouteDual("delete-sshkey", "api/sshkey",
                                        new { controller = "SSHKey", action = "DeleteKeyPair" },
                                        new { verb = new HttpMethodRouteConstraint("DELETE") });

                // Environment
                routes.MapHttpRouteDual("get-env", "environment", new { controller = "Environment", action = "Get" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });

                // Settings
                routes.MapHttpRouteDual("set-setting", "settings", new { controller = "Settings", action = "Set" },
                                        new { verb = new HttpMethodRouteConstraint("POST") });
                routes.MapHttpRouteDual("get-all-settings", "settings",
                                        new { controller = "Settings", action = "GetAll" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpRouteDual("get-setting", "settings/{key}", new { controller = "Settings", action = "Get" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpRouteDual("delete-setting", "settings/{key}",
                                        new { controller = "Settings", action = "Delete" },
                                        new { verb = new HttpMethodRouteConstraint("DELETE") });

                // Diagnostics
                routes.MapHttpRouteDual("diagnostics", "dump", new { controller = "Diagnostics", action = "GetLog" });
                routes.MapHttpRouteDual("diagnostics-set-setting", "diagnostics/settings",
                                        new { controller = "Diagnostics", action = "Set" },
                                        new { verb = new HttpMethodRouteConstraint("POST") });
                routes.MapHttpRouteDual("diagnostics-get-all-settings", "diagnostics/settings",
                                        new { controller = "Diagnostics", action = "GetAll" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpRouteDual("diagnostics-get-setting", "diagnostics/settings/{key}",
                                        new { controller = "Diagnostics", action = "Get" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpRouteDual("diagnostics-delete-setting", "diagnostics/settings/{key}",
                                        new { controller = "Diagnostics", action = "Delete" },
                                        new { verb = new HttpMethodRouteConstraint("DELETE") });

                // Logs
                foreach (var url in new[] { "/logstream", "/logstream/{*path}" })
                {
                    app.Map(url, appBranch => appBranch.RunLogStreamHandler());
                }

                routes.MapHttpRouteDual("recent-logs", "api/logs/recent",
                                        new { controller = "Diagnostics", action = "GetRecentLogs" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });

                // Enable these for Linux and Windows Containers.
                if (!OSDetector.IsOnWindows() || (OSDetector.IsOnWindows() && EnvironmentHelper.IsWindowsContainers()))
                {
                    routes.MapRoute("current-docker-logs-zip", "api/logs/docker/zip",
                                    new { controller = "Diagnostics", action = "GetDockerLogsZip" },
                                    new { verb = new HttpMethodRouteConstraint("GET") });
                    routes.MapRoute("current-docker-logs", "api/logs/docker",
                                    new { controller = "Diagnostics", action = "GetDockerLogs" },
                                    new { verb = new HttpMethodRouteConstraint("GET") });
                }

                var processControllerName = OSDetector.IsOnWindows() ? "Process" : "LinuxProcess";

                // Processes
                routes.MapHttpProcessesRoute("all-processes", "",
                                             new { controller = processControllerName, action = "GetAllProcesses" },
                                             new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpProcessesRoute("one-process-get", "/{id}",
                                             new { controller = processControllerName, action = "GetProcess" },
                                             new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpProcessesRoute("one-process-delete", "/{id}",
                                             new { controller = processControllerName, action = "KillProcess" },
                                             new { verb = new HttpMethodRouteConstraint("DELETE") });
                routes.MapHttpProcessesRoute("one-process-dump", "/{id}/dump",
                                             new { controller = processControllerName, action = "MiniDump" },
                                             new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpProcessesRoute("start-process-profile", "/{id}/profile/start",
                                             new { controller = processControllerName, action = "StartProfileAsync" },
                                             new { verb = new HttpMethodRouteConstraint("POST") });
                routes.MapHttpProcessesRoute("stop-process-profile", "/{id}/profile/stop",
                                             new { controller = processControllerName, action = "StopProfileAsync" },
                                             new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpProcessesRoute("all-threads", "/{id}/threads",
                                             new { controller = processControllerName, action = "GetAllThreads" },
                                             new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpProcessesRoute("one-process-thread", "/{processId}/threads/{threadId}",
                                             new { controller = processControllerName, action = "GetThread" },
                                             new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpProcessesRoute("all-modules", "/{id}/modules",
                                             new { controller = processControllerName, action = "GetAllModules" },
                                             new { verb = new HttpMethodRouteConstraint("GET") });
                routes.MapHttpProcessesRoute("one-process-module", "/{id}/modules/{baseAddress}",
                                             new { controller = processControllerName, action = "GetModule" },
                                             new { verb = new HttpMethodRouteConstraint("GET") });

                // Runtime
                routes.MapHttpRouteDual("runtime", "diagnostics/runtime",
                                        new { controller = "Runtime", action = "GetRuntimeVersions" },
                                        new { verb = new HttpMethodRouteConstraint("GET") });

                // Docker Hook Endpoint
                if (!OSDetector.IsOnWindows() || (OSDetector.IsOnWindows() && EnvironmentHelper.IsWindowsContainers()))
                {
                    routes.MapHttpRouteDual("docker", "docker/hook",
                                            new { controller = "Docker", action = "ReceiveHook" },
                                            new { verb = new HttpMethodRouteConstraint("POST") });
                }

                // catch all unregistered url to properly handle not found
                // routes.MapRoute("error-404", "{*path}", new {controller = "Error404", action = "Handle"});
            });

            Console.WriteLine(@"Exiting Configure : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));
        }
Exemplo n.º 7
0
        /// <summary>
        /// This method gets called by the runtime. It is used to add services
        /// to the container. It uses the Extension pattern.
        /// </summary>
        /// <todo>
        ///   CORE TODO Remove initializing contextAccessor : This is new. See if over time we can refactor away the need for this?
        ///   It's kind of a quick hack/compatibility shim. Ideally you want to get the request context only from where
        ///   it's specifically provided to you (Request.HttpContext in a controller, or as an Invoke() parameter in
        ///   a middleware) and pass it wherever its needed.
        /// </todo>
        public void ConfigureServices(IServiceCollection services)
        {
            Console.WriteLine("\nConfigure Services : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));

            services.Configure <FormOptions>(options =>
            {
                options.MultipartBodyLengthLimit = 52428800;
                options.ValueCountLimit          = 500000;
                options.KeyLengthLimit           = 500000;
            });


            services.AddMvcCore()
            .AddRazorPages()
            .AddAuthorization()
            .AddFormatterMappings()
            .AddJsonFormatters()
            .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());


            services.AddGZipCompression();

            services.AddDirectoryBrowser();

            services.AddDataProtection();

            var contextAccessor = new HttpContextAccessor();

            this._httpContextAccessor = contextAccessor;
            services.AddSingleton <IHttpContextAccessor>(contextAccessor);

            KuduWebUtil.EnsureHomeEnvironmentVariable();

            KuduWebUtil.EnsureSiteBitnessEnvironmentVariable();

            IEnvironment environment = KuduWebUtil.GetEnvironment(_hostingEnvironment);

            _webAppEnvironment = environment;

            KuduWebUtil.EnsureDotNetCoreEnvironmentVariable(environment);

            //CORE TODO Check this
            // fix up invalid /home/site/deployments/settings.xml
            KuduWebUtil.EnsureValidDeploymentXmlSettings(environment);

            // Add various folders that never change to the process path. All child processes will inherit this
            KuduWebUtil.PrependFoldersToPath(environment);

            // General
            services.AddSingleton <IServerConfiguration>(serverConfiguration);

            // CORE TODO Looks like this doesn't ever actually do anything, can refactor out?
            services.AddSingleton <IBuildPropertyProvider>(new BuildPropertyProvider());


            IDeploymentSettingsManager noContextDeploymentsSettingsManager =
                new DeploymentSettingsManager(new XmlSettings.Settings(KuduWebUtil.GetSettingsPath(environment)));

            TraceServices.TraceLevel = noContextDeploymentsSettingsManager.GetTraceLevel();

            // Per request environment
            services.AddScoped <IEnvironment>(sp => KuduWebUtil.GetEnvironment(_hostingEnvironment, sp.GetRequiredService <IDeploymentSettingsManager>(),
                                                                               sp.GetRequiredService <IHttpContextAccessor>().HttpContext));

            services.AddDeployementServices(environment);


            /*
             * CORE TODO all this business around ITracerFactory/ITracer/GetTracer()/
             * ILogger needs serious refactoring:
             * - Names should be changed to make it clearer that ILogger is for deployment
             * logging and ITracer and friends are for Kudu tracing
             * - ILogger is a first-class citizen in .NET core and has it's own meaning. We should be using it
             *   where appropriate (and not name-colliding with it)
             * - ITracer vs. ITraceFactory is redundant and confusing.
             * - All this stuff with funcs and factories and TraceServices is overcomplicated.
             * TraceServices only serves to confuse stuff now that we're avoiding
             */
            Func <IServiceProvider, ITracer> resolveTracer = sp => KuduWebUtil.GetTracer(sp);

            ITracer CreateTracerThunk() => resolveTracer(services.BuildServiceProvider());

            // First try to use the current request profiler if any, otherwise create a new one
            var traceFactory = new TracerFactory(() => {
                var sp      = services.BuildServiceProvider();
                var context = sp.GetRequiredService <IHttpContextAccessor>().HttpContext;
                return(TraceServices.GetRequestTracer(context) ?? resolveTracer(sp));
            });

            services.AddScoped <ITracer>(sp =>
            {
                var context = sp.GetRequiredService <IHttpContextAccessor>().HttpContext;
                return(TraceServices.GetRequestTracer(context) ?? NullTracer.Instance);
            });

            services.AddSingleton <ITraceFactory>(traceFactory);

            TraceServices.SetTraceFactory(CreateTracerThunk);

            services.AddSingleton <IDictionary <string, IOperationLock> >(KuduWebUtil.GetNamedLocks(traceFactory, environment));

            // CORE TODO ShutdownDetector, used by LogStreamManager.
            //var shutdownDetector = new ShutdownDetector();
            //shutdownDetector.Initialize()

            var noContextTraceFactory = new TracerFactory(() => KuduWebUtil.GetTracerWithoutContext(environment, noContextDeploymentsSettingsManager));
            var etwTraceFactory       = new TracerFactory(() => new ETWTracer(string.Empty, string.Empty));

            services.AddTransient <IAnalytics>(sp => new Analytics(sp.GetRequiredService <IDeploymentSettingsManager>(),
                                                                   sp.GetRequiredService <IServerConfiguration>(),
                                                                   noContextTraceFactory));

            // CORE TODO Trace unhandled exceptions
            //AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
            //{
            //    var ex = args.ExceptionObject as Exception;
            //    if (ex != null)
            //    {
            //        kernel.Get<IAnalytics>().UnexpectedException(ex);
            //    }
            //};

            // CORE TODO
            // Trace shutdown event
            // Cannot use shutdownDetector.Token.Register because of race condition
            // with NinjectServices.Stop via WebActivator.ApplicationShutdownMethodAttribute
            //Shutdown += () => TraceShutdown(environment, noContextDeploymentsSettingsManager);

            // CORE TODO
            // LogStream service
            // The hooks and log stream start endpoint are low traffic end-points. Re-using it to avoid creating another lock
            var logStreamManagerLock = KuduWebUtil.GetNamedLocks(traceFactory, environment)["hooks"];

            //kernel.Bind<LogStreamManager>().ToMethod(context => new LogStreamManager(Path.Combine(environment.RootPath, Constants.LogFilesPath),
            //                                                                         context.Kernel.Get<IEnvironment>(),
            //                                                                         context.Kernel.Get<IDeploymentSettingsManager>(),
            //                                                                         context.Kernel.Get<ITracer>(),
            //                                                                         shutdownDetector,
            //                                                                         logStreamManagerLock));

            services.AddTransient(sp => new LogStreamManager(Path.Combine(environment.RootPath, Constants.LogFilesPath),
                                                             sp.GetRequiredService <IEnvironment>(),
                                                             sp.GetRequiredService <IDeploymentSettingsManager>(),
                                                             sp.GetRequiredService <ITracer>(),
                                                             logStreamManagerLock));

            // CORE TODO Need to implement this, and same comment as in InfoRefsController.cs (not sure why it needs the kernel/iserviceprovider as a
            // service locator, why does it need "delayed binding"?)
            //kernel.Bind<CustomGitRepositoryHandler>().ToMethod(context => new CustomGitRepositoryHandler(t => context.Kernel.Get(t)))
            //                                         .InRequestScope();

            // Deployment Service

            services.AddWebJobsDependencies();

            services.AddScoped <ILogger>(sp => KuduWebUtil.GetLogger(sp));

            services.AddScoped <IDeploymentManager, DeploymentManager>();
            services.AddScoped <IFetchDeploymentManager, FetchDeploymentManager>();
            services.AddScoped <ISSHKeyManager, SSHKeyManager>();

            services.AddScoped <IRepositoryFactory>(sp => KuduWebUtil.GetDeploymentLock(traceFactory, environment).RepositoryFactory = new RepositoryFactory(
                                                        sp.GetRequiredService <IEnvironment>(), sp.GetRequiredService <IDeploymentSettingsManager>(), sp.GetRequiredService <ITraceFactory>()));

            // CORE NOTE This was previously wired up in Ninject with .InSingletonScope. I'm not sure how that worked,
            // since it depends on an IEnvironment, which was set up with .PerRequestScope. I have made this per request.
            services.AddScoped <IApplicationLogsReader, ApplicationLogsReader>();

            // Git server
            services.AddGitServer(KuduWebUtil.GetDeploymentLock(traceFactory, environment));

            // Git Servicehook Parsers
            services.AddGitServiceHookParsers();

            // CORE TODO
            // SiteExtensions
            //kernel.Bind<ISiteExtensionManager>().To<SiteExtensionManager>().InRequestScope();

            // CORE TODO
            // Functions
            //kernel.Bind<IFunctionManager>().To<FunctionManager>().InRequestScope();

            services.AddScoped <ICommandExecutor, CommandExecutor>();

            // CORE TODO This stuff should probably go in a separate method
            // (they don't really fit into "ConfigureServices"), and much of it is probably no longer needed
            //MigrateSite(environment, noContextDeploymentsSettingsManager);
            //RemoveOldTracePath(environment);
            //RemoveTempFileFromUserDrive(environment);

            //// Temporary fix for https://github.com/npm/npm/issues/5905
            //EnsureNpmGlobalDirectory();
            //EnsureUserProfileDirectory();

            //// Skip SSL Certificate Validate
            //if (Kudu.Core.Environment.SkipSslValidation)
            //{
            //     ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            //}

            //// Make sure webpages:Enabled is true. Even though we set it in web.config, it could be overwritten by
            //// an Azure AppSetting that's supposed to be for the site only but incidently affects Kudu as well.
            ConfigurationManager.AppSettings["webpages:Enabled"] = "true";

            //// Kudu does not rely owin:appStartup.  This is to avoid Azure AppSetting if set.
            if (ConfigurationManager.AppSettings?["owin:appStartup"] != null)
            {
                // Set the appSetting to null since we cannot use AppSettings.Remove(key) (ReadOnly exception!)
                ConfigurationManager.AppSettings["owin:appStartup"] = null;
            }

            //RegisterRoutes(kernel, RouteTable.Routes);

            //// Register the default hubs route: ~/signalr
            //GlobalHost.DependencyResolver = new SignalRNinjectDependencyResolver(kernel);
            //GlobalConfiguration.Configuration.Filters.Add(
            //    new TraceDeprecatedActionAttribute(
            //        kernel.Get<IAnalytics>(),
            //        kernel.Get<ITraceFactory>()));
            //GlobalConfiguration.Configuration.Filters.Add(new EnsureRequestIdHandlerAttribute());

            //FileTarget target = LogManager.Configuration.FindTargetByName("file") as FileTarget;
            //String logfile = _webAppEnvironment.LogFilesPath + "/.txt";
            //target.FileName = logfile;
        }