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); 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 IFileSystem fileSystem = new FileSystem(); TraceLevel level = settingsManager.GetTraceLevel(); ITracer tracer = GetTracer(env, level, fileSystem); 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); IOperationLock deploymentLock = new LockFile(deploymentLockPath, traceFactory, fileSystem); IOperationLock statusLock = new LockFile(statusLockPath, traceFactory, fileSystem); IBuildPropertyProvider buildPropertyProvider = new BuildPropertyProvider(); ISiteBuilderFactory builderFactory = new SiteBuilderFactory(buildPropertyProvider, env); IRepository gitRepository = new GitExeRepository(env, settingsManager, traceFactory); var logger = new ConsoleLogger(); IDeploymentManager deploymentManager = new DeploymentManager(builderFactory, env, fileSystem, traceFactory, settingsManager, new DeploymentStatusManager(env, fileSystem, statusLock), 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(gitRepository, changeSet: null, deployer: deployer, clean: false); } catch (Exception e) { System.Console.Error.WriteLine(e.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 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"; 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); // 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(); 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>())) .InRequestScope(); // General 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); 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)); 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( noContextTraceFactory, kernel.Get<IEnvironment>(), kernel.Get<IDeploymentSettingsManager>(), kernel.Get<IAnalytics>(), kernel.Get<IWebHooksManager>()); kernel.Bind<ITriggeredJobsManager>().ToConstant(triggeredJobsManager) .InTransientScope(); TriggeredJobsScheduler triggeredJobsScheduler = new TriggeredJobsScheduler( triggeredJobsManager, noContextTraceFactory, environment, kernel.Get<IAnalytics>()); kernel.Bind<TriggeredJobsScheduler>().ToConstant(triggeredJobsScheduler) .InTransientScope(); IContinuousJobsManager continuousJobManager = new ContinuousJobsManager( noContextTraceFactory, 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<IAutoSwapHandler>().To<AutoSwapHandler>() .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 OperationClient.SkipSslValidationIfNeeded(); // 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()); }