public DeploymentSettingsPrioritiesTests() { var settingsPriority1 = new Dictionary <string, string>(); settingsPriority1["key1"] = "settingsPriority1_value1"; settingsPriority1["key2"] = "settingsPriority1_value2"; settingsPriority1["key3"] = "settingsPriority1_value3"; settingsPriority1["key4"] = "settingsPriority1_value4"; var settingsPriority2 = new Dictionary <string, string>(); settingsPriority1["key2"] = "settingsPriority2_value2"; settingsPriority1["key3"] = "settingsPriority2_value3"; settingsPriority1["key5"] = "settingsPriority2_value5"; settingsPriority1["key6"] = "settingsPriority2_value6"; var settingsPriority50 = new Dictionary <string, string>(); settingsPriority1["key1"] = "settingsPriority50_value1"; settingsPriority1["key2"] = "settingsPriority50_value2"; settingsPriority1["key5"] = "settingsPriority50_value5"; settingsPriority1["key7"] = "settingsPriority50_value7"; var testProvider1 = new BasicSettingsProvider(settingsPriority1, (SettingsProvidersPriority)1); var testProvider2 = new BasicSettingsProvider(settingsPriority2, (SettingsProvidersPriority)2); var testProvider50 = new BasicSettingsProvider(settingsPriority50, (SettingsProvidersPriority)50); var settingsProviders = new ISettingsProvider[] { testProvider1, testProvider50, testProvider2 }; PerSiteSettingsProvider perSiteSettings = null; deploymentSettingsManager = new DeploymentSettingsManager(perSiteSettings, settingsProviders); }
/// <summary> /// Ensures valid /home/site/deployments/settings.xml is loaded, deletes /// corrupt settings.xml file /// </summary> /// <param name="environment"> /// IEnvironment object that maintains paths used by kudu /// </param> internal static void EnsureValidDeploymentXmlSettings(IEnvironment environment) { var path = GetSettingsPath(environment); if (!FileSystemHelpers.FileExists(path)) { return; } try { var settings = new DeploymentSettingsManager(new XmlSettings.Settings(path)); settings.GetValue(SettingsKeys.TraceLevel); } catch (Exception ex) { DateTime lastWriteTimeUtc = DateTime.MinValue; OperationManager.SafeExecute(() => lastWriteTimeUtc = File.GetLastWriteTimeUtc(path)); // trace initialization error KuduEventSource.Log.KuduException( ServerConfiguration.GetApplicationName(), "Startup.cs", string.Empty, string.Empty, string.Format("Invalid '{0}' is detected and deleted. Last updated time was {1}.", path, lastWriteTimeUtc), ex.ToString()); File.Delete(path); } }
public void AllowShallowClonesReturnsFalseForNonTrueLikeValues(string value) { // Arrange var settings = new Mock <ISettings>(MockBehavior.Strict); settings.Setup(s => s.GetValue("deployment", "SCM_USE_SHALLOW_CLONE")).Returns(value); var deploymentSettings = new DeploymentSettingsManager(settings.Object, DefaultSettingsProvider); // Act bool result = deploymentSettings.AllowShallowClones(); // Assert Assert.False(result); }
public void GetBranchUsesPersistedBranchValueIfAvailable() { // Arrange var settings = new Mock <ISettings>(); settings.Setup(s => s.GetValue("deployment", "branch")).Returns("my-branch"); var deploymentSettings = new DeploymentSettingsManager(settings.Object, DefaultSettingsProvider); // Act string branch = deploymentSettings.GetBranch(); // Assert Assert.Equal("my-branch", branch); }
public void SetBranchClearsLegacyKeyIfPresent() { // Arrange var settings = new Mock <ISettings>(MockBehavior.Strict); settings.Setup(s => s.DeleteValue("deployment", "branch")).Returns(true).Verifiable(); settings.Setup(s => s.SetValue("deployment", "deployment_branch", "my-branch")).Verifiable(); var deploymentSettings = new DeploymentSettingsManager(settings.Object, DefaultSettingsProvider); // Act deploymentSettings.SetBranch("my-branch"); // Assert settings.Verify(); }
public void GetBranchDoesNotUnifyValuesWithLegacyKey() { // Arrange var settings = Mock.Of <ISettings>(); var defaultSettings = new Dictionary <string, string> { { "deployment_branch", "my-deployment-branch" }, { "branch", "my-legacy-branch" } }; var deploymentSettings = new DeploymentSettingsManager(settings, BuildSettingsProviders(defaultSettings)); // Act string branch = deploymentSettings.GetBranch(); // Assert Assert.Equal("my-deployment-branch", branch); }
public void GetBranchUsesLegacyBranchValueIfDeploymentBranchIsOnlyAvailableAsPartOfEnvironment() { // Arrange var settings = new Mock <ISettings>(); var defaultSettings = new Dictionary <string, string> { { "deployment_branch", "my-deployment-branch" } }; settings.Setup(s => s.GetValue("deployment", "branch")).Returns("my-branch"); var deploymentSettings = new DeploymentSettingsManager(settings.Object, BuildSettingsProviders(defaultSettings)); // Act string branch = deploymentSettings.GetBranch(); // Assert Assert.Equal("my-branch", branch); }
private static void RegisterServices(IKernel kernel) { var serverConfiguration = new ServerConfiguration(); // Make sure %HOME% is correctly set EnsureHomeEnvironmentVariable(); EnsureSiteBitnessEnvironmentVariable(); IEnvironment environment = GetEnvironment(); EnsureDotNetCoreEnvironmentVariable(environment); // Add various folders that never change to the process path. All child processes will inherit PrependFoldersToPath(environment); // Per request environment kernel.Bind <IEnvironment>().ToMethod(context => GetEnvironment(context.Kernel.Get <IDeploymentSettingsManager>(), HttpContext.Current)) .InRequestScope(); // General kernel.Bind <IServerConfiguration>().ToConstant(serverConfiguration); kernel.Bind <IBuildPropertyProvider>().ToConstant(new BuildPropertyProvider()); System.Func <ITracer> createTracerThunk = () => GetTracer(kernel); // First try to use the current request profiler if any, otherwise create a new one var traceFactory = new TracerFactory(() => TraceServices.CurrentRequestTracer ?? createTracerThunk()); kernel.Bind <ITracer>().ToMethod(context => TraceServices.CurrentRequestTracer ?? NullTracer.Instance); kernel.Bind <ITraceFactory>().ToConstant(traceFactory); TraceServices.SetTraceFactory(createTracerThunk); // Setup the deployment lock string lockPath = Path.Combine(environment.SiteRootPath, Constants.LockPath); string deploymentLockPath = Path.Combine(lockPath, Constants.DeploymentLockFile); string statusLockPath = Path.Combine(lockPath, Constants.StatusLockFile); string sshKeyLockPath = Path.Combine(lockPath, Constants.SSHKeyLockFile); string hooksLockPath = Path.Combine(lockPath, Constants.HooksLockFile); _deploymentLock = new DeploymentLockFile(deploymentLockPath, kernel.Get <ITraceFactory>()); _deploymentLock.InitializeAsyncLocks(); var statusLock = new LockFile(statusLockPath, kernel.Get <ITraceFactory>()); var sshKeyLock = new LockFile(sshKeyLockPath, kernel.Get <ITraceFactory>()); var hooksLock = new LockFile(hooksLockPath, kernel.Get <ITraceFactory>()); kernel.Bind <IOperationLock>().ToConstant(sshKeyLock).WhenInjectedInto <SSHKeyController>(); kernel.Bind <IOperationLock>().ToConstant(statusLock).WhenInjectedInto <DeploymentStatusManager>(); kernel.Bind <IOperationLock>().ToConstant(hooksLock).WhenInjectedInto <WebHooksManager>(); kernel.Bind <IOperationLock>().ToConstant(_deploymentLock); var shutdownDetector = new ShutdownDetector(); shutdownDetector.Initialize(); IDeploymentSettingsManager noContextDeploymentsSettingsManager = new DeploymentSettingsManager(new XmlSettings.Settings(GetSettingsPath(environment))); TraceServices.TraceLevel = noContextDeploymentsSettingsManager.GetTraceLevel(); var noContextTraceFactory = new TracerFactory(() => GetTracerWithoutContext(environment, noContextDeploymentsSettingsManager)); var etwTraceFactory = new TracerFactory(() => new ETWTracer(string.Empty, string.Empty)); kernel.Bind <IAnalytics>().ToMethod(context => new Analytics(context.Kernel.Get <IDeploymentSettingsManager>(), context.Kernel.Get <IServerConfiguration>(), noContextTraceFactory)); // Trace unhandled (crash) exceptions. AppDomain.CurrentDomain.UnhandledException += (sender, args) => { var ex = args.ExceptionObject as Exception; if (ex != null) { kernel.Get <IAnalytics>().UnexpectedException(ex); } }; // Trace shutdown event // Cannot use shutdownDetector.Token.Register because of race condition // with NinjectServices.Stop via WebActivator.ApplicationShutdownMethodAttribute Shutdown += () => TraceShutdown(environment, noContextDeploymentsSettingsManager); // LogStream service // The hooks and log stream start endpoint are low traffic end-points. Re-using it to avoid creating another lock var logStreamManagerLock = hooksLock; 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)); kernel.Bind <InfoRefsController>().ToMethod(context => new InfoRefsController(t => context.Kernel.Get(t))) .InRequestScope(); kernel.Bind <CustomGitRepositoryHandler>().ToMethod(context => new CustomGitRepositoryHandler(t => context.Kernel.Get(t))) .InRequestScope(); // Deployment Service kernel.Bind <ISettings>().ToMethod(context => new XmlSettings.Settings(GetSettingsPath(environment))) .InRequestScope(); kernel.Bind <IDeploymentSettingsManager>().To <DeploymentSettingsManager>() .InRequestScope(); kernel.Bind <IDeploymentStatusManager>().To <DeploymentStatusManager>() .InRequestScope(); kernel.Bind <ISiteBuilderFactory>().To <SiteBuilderFactory>() .InRequestScope(); kernel.Bind <IWebHooksManager>().To <WebHooksManager>() .InRequestScope(); ITriggeredJobsManager triggeredJobsManager = new TriggeredJobsManager( etwTraceFactory, kernel.Get <IEnvironment>(), kernel.Get <IDeploymentSettingsManager>(), kernel.Get <IAnalytics>(), kernel.Get <IWebHooksManager>()); kernel.Bind <ITriggeredJobsManager>().ToConstant(triggeredJobsManager) .InTransientScope(); TriggeredJobsScheduler triggeredJobsScheduler = new TriggeredJobsScheduler( triggeredJobsManager, etwTraceFactory, environment, kernel.Get <IDeploymentSettingsManager>(), kernel.Get <IAnalytics>()); kernel.Bind <TriggeredJobsScheduler>().ToConstant(triggeredJobsScheduler) .InTransientScope(); IContinuousJobsManager continuousJobManager = new ContinuousJobsManager( etwTraceFactory, kernel.Get <IEnvironment>(), kernel.Get <IDeploymentSettingsManager>(), kernel.Get <IAnalytics>()); OperationManager.SafeExecute(triggeredJobsManager.CleanupDeletedJobs); OperationManager.SafeExecute(continuousJobManager.CleanupDeletedJobs); kernel.Bind <IContinuousJobsManager>().ToConstant(continuousJobManager) .InTransientScope(); kernel.Bind <ILogger>().ToMethod(context => GetLogger(environment, context.Kernel)) .InRequestScope(); kernel.Bind <IDeploymentManager>().To <DeploymentManager>() .InRequestScope(); kernel.Bind <IFetchDeploymentManager>().To <FetchDeploymentManager>() .InRequestScope(); kernel.Bind <ISSHKeyManager>().To <SSHKeyManager>() .InRequestScope(); kernel.Bind <IRepositoryFactory>().ToMethod(context => _deploymentLock.RepositoryFactory = new RepositoryFactory(context.Kernel.Get <IEnvironment>(), context.Kernel.Get <IDeploymentSettingsManager>(), context.Kernel.Get <ITraceFactory>())) .InRequestScope(); kernel.Bind <IApplicationLogsReader>().To <ApplicationLogsReader>() .InSingletonScope(); // Git server kernel.Bind <IDeploymentEnvironment>().To <DeploymentEnvrionment>(); kernel.Bind <IGitServer>().ToMethod(context => new GitExeServer(context.Kernel.Get <IEnvironment>(), _deploymentLock, GetRequestTraceFile(context.Kernel), context.Kernel.Get <IRepositoryFactory>(), context.Kernel.Get <IDeploymentEnvironment>(), context.Kernel.Get <IDeploymentSettingsManager>(), context.Kernel.Get <ITraceFactory>())) .InRequestScope(); // Git Servicehook parsers kernel.Bind <IServiceHookHandler>().To <GenericHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <GitHubHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <BitbucketHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <BitbucketHandlerV2>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <DropboxHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <CodePlexHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <CodebaseHqHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <GitlabHqHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <GitHubCompatHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <KilnHgHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <VSOHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <OneDriveHandler>().InRequestScope(); // SiteExtensions kernel.Bind <ISiteExtensionManager>().To <SiteExtensionManager>().InRequestScope(); // Functions kernel.Bind <IFunctionManager>().To <FunctionManager>().InRequestScope(); // Command executor kernel.Bind <ICommandExecutor>().To <CommandExecutor>().InRequestScope(); 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()); }
private static int Main(string[] args) { // Turn flag on in app.config to wait for debugger on launch if (ConfigurationManager.AppSettings["WaitForDebuggerOnStart"] == "true") { while (!Debugger.IsAttached) { System.Threading.Thread.Sleep(100); } } if (System.Environment.GetEnvironmentVariable(SettingsKeys.DisableDeploymentOnPush) == "1") { return(0); } if (args.Length < 2) { System.Console.WriteLine("Usage: kudu.exe appRoot wapTargets [deployer]"); return(1); } // The post receive hook launches the exe from sh and intereprets newline differently. // This fixes very wacky issues with how the output shows up in the console on push System.Console.Error.NewLine = "\n"; System.Console.Out.NewLine = "\n"; System.Environment.SetEnvironmentVariable("GIT_DIR", null, System.EnvironmentVariableTarget.Process); // Skip SSL Certificate Validate OperationClient.SkipSslValidationIfNeeded(); string appRoot = args[0]; string wapTargets = args[1]; string deployer = args.Length == 2 ? null : args[2]; IEnvironment env = GetEnvironment(appRoot); ISettings settings = new XmlSettings.Settings(GetSettingsPath(env)); IDeploymentSettingsManager settingsManager = new DeploymentSettingsManager(settings); // Adjust repo path env.RepositoryPath = Path.Combine(env.SiteRootPath, settingsManager.GetRepositoryPath()); // Setup the trace TraceLevel level = settingsManager.GetTraceLevel(); ITracer tracer = GetTracer(env, level); ITraceFactory traceFactory = new TracerFactory(() => tracer); // Calculate the lock path string lockPath = Path.Combine(env.SiteRootPath, Constants.LockPath); string deploymentLockPath = Path.Combine(lockPath, Constants.DeploymentLockFile); string statusLockPath = Path.Combine(lockPath, Constants.StatusLockFile); string hooksLockPath = Path.Combine(lockPath, Constants.HooksLockFile); IOperationLock deploymentLock = new LockFile(deploymentLockPath, traceFactory); IOperationLock statusLock = new LockFile(statusLockPath, traceFactory); IOperationLock hooksLock = new LockFile(hooksLockPath, traceFactory); IBuildPropertyProvider buildPropertyProvider = new BuildPropertyProvider(); ISiteBuilderFactory builderFactory = new SiteBuilderFactory(buildPropertyProvider, env); IRepository gitRepository; if (settingsManager.UseLibGit2SharpRepository()) { gitRepository = new LibGit2SharpRepository(env, settingsManager, traceFactory); } else { gitRepository = new GitExeRepository(env, settingsManager, traceFactory); } IServerConfiguration serverConfiguration = new ServerConfiguration(); IAnalytics analytics = new Analytics(settingsManager, serverConfiguration, traceFactory); IWebHooksManager hooksManager = new WebHooksManager(tracer, env, hooksLock); IDeploymentStatusManager deploymentStatusManager = new DeploymentStatusManager(env, analytics, statusLock); IAutoSwapHandler autoSwapHander = new AutoSwapHandler(deploymentStatusManager, env, settingsManager, traceFactory); var functionManager = new FunctionManager(env, traceFactory); var logger = new ConsoleLogger(); IDeploymentManager deploymentManager = new DeploymentManager(builderFactory, env, traceFactory, analytics, settingsManager, deploymentStatusManager, deploymentLock, GetLogger(env, level, logger), hooksManager, autoSwapHander, functionManager); var step = tracer.Step(XmlTracer.ExecutingExternalProcessTrace, new Dictionary <string, string> { { "type", "process" }, { "path", "kudu.exe" }, { "arguments", appRoot + " " + wapTargets } }); using (step) { try { deploymentManager.DeployAsync(gitRepository, changeSet: null, deployer: deployer, clean: false) .Wait(); } catch (Exception e) { tracer.TraceError(e); System.Console.Error.WriteLine(e.GetBaseException().Message); System.Console.Error.WriteLine(Resources.Log_DeploymentError); return(1); } } if (logger.HasErrors) { System.Console.Error.WriteLine(Resources.Log_DeploymentError); return(1); } return(0); }
private static int Main(string[] args) { // Turn flag on in app.config to wait for debugger on launch if (ConfigurationManager.AppSettings["WaitForDebuggerOnStart"] == "true") { while (!Debugger.IsAttached) { System.Threading.Thread.Sleep(100); } } if (System.Environment.GetEnvironmentVariable(SettingsKeys.DisableDeploymentOnPush) == "1") { return(0); } if (args.Length < 2) { System.Console.WriteLine("Usage: kudu.exe appRoot wapTargets [deployer]"); return(1); } // The post receive hook launches the exe from sh and interprets newline differently. // This fixes very wacky issues with how the output shows up in the console on push System.Console.Error.NewLine = "\n"; System.Console.Out.NewLine = "\n"; string appRoot = args[0]; string wapTargets = args[1]; string deployer = args.Length == 2 ? null : args[2]; string requestId = System.Environment.GetEnvironmentVariable(Constants.RequestIdHeader); IEnvironment env = GetEnvironment(appRoot, requestId); ISettings settings = new XmlSettings.Settings(GetSettingsPath(env)); IDeploymentSettingsManager settingsManager = new DeploymentSettingsManager(settings); // Setup the trace TraceLevel level = settingsManager.GetTraceLevel(); ITracer tracer = GetTracer(env, level); ITraceFactory traceFactory = new TracerFactory(() => tracer); // Calculate the lock path string lockPath = Path.Combine(env.SiteRootPath, Constants.LockPath); string deploymentLockPath = Path.Combine(lockPath, Constants.DeploymentLockFile); IOperationLock deploymentLock = new LockFile(deploymentLockPath, traceFactory); if (deploymentLock.IsHeld) { return(PerformDeploy(appRoot, wapTargets, deployer, lockPath, env, settingsManager, level, tracer, traceFactory, deploymentLock)); } // Cross child process lock is not working on linux via mono. // When we reach here, deployment lock must be HELD! To solve above issue, we lock again before continue. try { return(deploymentLock.LockOperation(() => { return PerformDeploy(appRoot, wapTargets, deployer, lockPath, env, settingsManager, level, tracer, traceFactory, deploymentLock); }, "Performing deployment", TimeSpan.Zero)); } catch (LockOperationException) { return(-1); } }
private static void RegisterServices(IKernel kernel) { var serverConfiguration = new ServerConfiguration(); // Make sure %HOME% is correctly set EnsureHomeEnvironmentVariable(); IEnvironment environment = GetEnvironment(); // Per request environment kernel.Bind <IEnvironment>().ToMethod(context => GetEnvironment(context.Kernel.Get <IDeploymentSettingsManager>())) .InRequestScope(); // General kernel.Bind <HttpContextBase>().ToMethod(context => new HttpContextWrapper(HttpContext.Current)) .InRequestScope(); kernel.Bind <IServerConfiguration>().ToConstant(serverConfiguration); kernel.Bind <IBuildPropertyProvider>().ToConstant(new BuildPropertyProvider()); System.Func <ITracer> createTracerThunk = () => GetTracer(environment, kernel); System.Func <ILogger> createLoggerThunk = () => GetLogger(environment, kernel); // First try to use the current request profiler if any, otherwise create a new one var traceFactory = new TracerFactory(() => TraceServices.CurrentRequestTracer ?? createTracerThunk()); kernel.Bind <ITracer>().ToMethod(context => TraceServices.CurrentRequestTracer ?? NullTracer.Instance); kernel.Bind <ITraceFactory>().ToConstant(traceFactory); TraceServices.SetTraceFactory(createTracerThunk, createLoggerThunk); // Setup the deployment lock string lockPath = Path.Combine(environment.SiteRootPath, Constants.LockPath); string deploymentLockPath = Path.Combine(lockPath, Constants.DeploymentLockFile); string statusLockPath = Path.Combine(lockPath, Constants.StatusLockFile); string sshKeyLockPath = Path.Combine(lockPath, Constants.SSHKeyLockFile); string hooksLockPath = Path.Combine(lockPath, Constants.HooksLockFile); _deploymentLock = new DeploymentLockFile(deploymentLockPath, kernel.Get <ITraceFactory>()); _deploymentLock.InitializeAsyncLocks(); var statusLock = new LockFile(statusLockPath, kernel.Get <ITraceFactory>()); var sshKeyLock = new LockFile(sshKeyLockPath, kernel.Get <ITraceFactory>()); var hooksLock = new LockFile(hooksLockPath, kernel.Get <ITraceFactory>()); kernel.Bind <IOperationLock>().ToConstant(sshKeyLock).WhenInjectedInto <SSHKeyController>(); kernel.Bind <IOperationLock>().ToConstant(statusLock).WhenInjectedInto <DeploymentStatusManager>(); kernel.Bind <IOperationLock>().ToConstant(hooksLock).WhenInjectedInto <WebHooksManager>(); kernel.Bind <IOperationLock>().ToConstant(_deploymentLock); kernel.Bind <IAnalytics>().ToMethod(context => new Analytics(context.Kernel.Get <IDeploymentSettingsManager>(), context.Kernel.Get <ITracer>(), environment.AnalyticsPath)); var shutdownDetector = new ShutdownDetector(); shutdownDetector.Initialize(); IDeploymentSettingsManager noContextDeploymentsSettingsManager = new DeploymentSettingsManager(new XmlSettings.Settings(GetSettingsPath(environment))); // Trace shutdown event // Cannot use shutdownDetector.Token.Register because of race condition // with NinjectServices.Stop via WebActivator.ApplicationShutdownMethodAttribute Shutdown += () => TraceShutdown(environment, noContextDeploymentsSettingsManager); // LogStream service // The hooks and log stream start endpoint are low traffic end-points. Re-using it to avoid creating another lock var logStreamManagerLock = hooksLock; 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)); kernel.Bind <InfoRefsController>().ToMethod(context => new InfoRefsController(t => context.Kernel.Get(t))) .InRequestScope(); kernel.Bind <CustomGitRepositoryHandler>().ToMethod(context => new CustomGitRepositoryHandler(t => context.Kernel.Get(t))) .InRequestScope(); // Deployment Service kernel.Bind <ISettings>().ToMethod(context => new XmlSettings.Settings(GetSettingsPath(environment))) .InRequestScope(); kernel.Bind <IDeploymentSettingsManager>().To <DeploymentSettingsManager>() .InRequestScope(); kernel.Bind <IDeploymentStatusManager>().To <DeploymentStatusManager>() .InRequestScope(); kernel.Bind <ISiteBuilderFactory>().To <SiteBuilderFactory>() .InRequestScope(); kernel.Bind <IWebHooksManager>().To <WebHooksManager>() .InRequestScope(); var noContextTraceFactory = new TracerFactory(() => GetTracerWithoutContext(environment, noContextDeploymentsSettingsManager)); ITriggeredJobsManager triggeredJobsManager = new TriggeredJobsManager( noContextTraceFactory, kernel.Get <IEnvironment>(), kernel.Get <IDeploymentSettingsManager>(), kernel.Get <IAnalytics>(), kernel.Get <IWebHooksManager>()); kernel.Bind <ITriggeredJobsManager>().ToConstant(triggeredJobsManager) .InTransientScope(); IContinuousJobsManager continuousJobManager = new ContinuousJobsManager( noContextTraceFactory, kernel.Get <IEnvironment>(), kernel.Get <IDeploymentSettingsManager>(), kernel.Get <IAnalytics>()); kernel.Bind <IContinuousJobsManager>().ToConstant(continuousJobManager) .InTransientScope(); kernel.Bind <ILogger>().ToMethod(context => GetLogger(environment, context.Kernel)) .InRequestScope(); kernel.Bind <IRepository>().ToMethod(context => new GitExeRepository(context.Kernel.Get <IEnvironment>(), context.Kernel.Get <IDeploymentSettingsManager>(), context.Kernel.Get <ITraceFactory>())) .InRequestScope(); kernel.Bind <IDeploymentManager>().To <DeploymentManager>() .InRequestScope(); kernel.Bind <ISSHKeyManager>().To <SSHKeyManager>() .InRequestScope(); kernel.Bind <IRepositoryFactory>().ToMethod(context => _deploymentLock.RepositoryFactory = new RepositoryFactory(context.Kernel.Get <IEnvironment>(), context.Kernel.Get <IDeploymentSettingsManager>(), context.Kernel.Get <ITraceFactory>(), context.Kernel.Get <HttpContextBase>())) .InRequestScope(); kernel.Bind <IApplicationLogsReader>().To <ApplicationLogsReader>() .InSingletonScope(); // Git server kernel.Bind <IDeploymentEnvironment>().To <DeploymentEnvrionment>(); kernel.Bind <IGitServer>().ToMethod(context => new GitExeServer(context.Kernel.Get <IEnvironment>(), _deploymentLock, GetRequestTraceFile(context.Kernel), context.Kernel.Get <IRepositoryFactory>(), context.Kernel.Get <IDeploymentEnvironment>(), context.Kernel.Get <IDeploymentSettingsManager>(), context.Kernel.Get <ITraceFactory>())) .InRequestScope(); // Git Servicehook parsers kernel.Bind <IServiceHookHandler>().To <GenericHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <GitHubHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <BitbucketHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <DropboxHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <CodePlexHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <CodebaseHqHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <GitlabHqHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <GitHubCompatHandler>().InRequestScope(); kernel.Bind <IServiceHookHandler>().To <KilnHgHandler>().InRequestScope(); // SiteExtensions kernel.Bind <ISiteExtensionManager>().To <SiteExtensionManager>().InRequestScope(); // Command executor kernel.Bind <ICommandExecutor>().ToMethod(context => GetCommandExecutor(environment, context)) .InRequestScope(); MigrateSite(environment, noContextDeploymentsSettingsManager); RegisterRoutes(kernel, RouteTable.Routes); // Register the default hubs route: ~/signalr GlobalHost.DependencyResolver = new SignalRNinjectDependencyResolver(kernel); RouteTable.Routes.MapConnection <PersistentCommandController>("commandstream", "/commandstream"); RouteTable.Routes.MapHubs("/filesystemhub", new HubConfiguration()); }
static int Main(string[] args) { // Turn flag on in app.config to wait for debugger on launch if (ConfigurationManager.AppSettings["WaitForDebuggerOnStart"] == "true") { while (!Debugger.IsAttached) { System.Threading.Thread.Sleep(100); } } if (args.Length < 2) { System.Console.WriteLine("Usage: kudu.exe appRoot wapTargets [deployer]"); return(1); } // The post receive hook launches the exe from sh and intereprets newline differently. // This fixes very wacky issues with how the output shows up in the conosle on push System.Console.Error.NewLine = "\n"; System.Console.Out.NewLine = "\n"; System.Environment.SetEnvironmentVariable("GIT_DIR", null, System.EnvironmentVariableTarget.Process); var appRoot = args[0]; var wapTargets = args[1]; string deployer = args.Length == 2 ? null : args[2]; string nugetCachePath = null; IEnvironment env = GetEnvironment(appRoot, nugetCachePath); var settings = new XmlSettings.Settings(GetSettingsPath(env)); var settingsManager = new DeploymentSettingsManager(settings); // Setup the trace TraceLevel level = settingsManager.GetTraceLevel(); var tracer = GetTracer(env, level); var traceFactory = new TracerFactory(() => tracer); // Calculate the lock path string lockPath = Path.Combine(env.SiteRootPath, Constants.LockPath); string deploymentLockPath = Path.Combine(lockPath, Constants.DeploymentLockFile); var deploymentLock = new LockFile(traceFactory, deploymentLockPath); var fs = new FileSystem(); var buildPropertyProvider = new BuildPropertyProvider(); var serverRepository = new GitDeploymentRepository(env.RepositoryPath, env.SiteRootPath, traceFactory); var builderFactory = new SiteBuilderFactory(settingsManager, buildPropertyProvider, env); var logger = new ConsoleLogger(); var deploymentManager = new DeploymentManager(serverRepository, builderFactory, env, fs, traceFactory, settingsManager, deploymentLock, GetLogger(env, level, logger)); var step = tracer.Step("Executing external process", new Dictionary <string, string> { { "type", "process" }, { "path", "kudu.exe" }, { "arguments", appRoot + " " + wapTargets } }); using (step) { try { deploymentManager.Deploy(deployer); } catch { System.Console.Error.WriteLine(Resources.Log_DeploymentError); throw; } } if (logger.HasErrors) { System.Console.Error.WriteLine(Resources.Log_DeploymentError); return(1); } return(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; }