public void ReturnsEmptyWhenNoDeploymentsPathConfigured() { var fileSystem = new Mock <IMeshPersistentFileSystem>(MockBehavior.Strict); fileSystem.Setup(f => f.GetDeploymentsPath()).Returns(string.Empty); var fileSystemPathProvider = new FileSystemPathProvider(fileSystem.Object); Assert.False(fileSystemPathProvider.TryGetDeploymentsPath(out string actualDeploymentsPath)); Assert.Equal(string.Empty, actualDeploymentsPath); }
public void ReturnsDeploymentsPath() { const string deploymentsPath = "/path-0"; var mockFileSystem = new Mock <IFileSystem>(MockBehavior.Strict); var directory = new Mock <DirectoryBase>(MockBehavior.Strict); directory.Setup(d => d.Exists(deploymentsPath)).Returns(true); mockFileSystem.SetupGet(f => f.Directory).Returns(directory.Object); using (new MockFileSystem(mockFileSystem.Object)) { var fileSystem = new Mock <IMeshPersistentFileSystem>(MockBehavior.Strict); const string expectedDeploymentsPath = deploymentsPath; fileSystem.Setup(f => f.GetDeploymentsPath()).Returns(expectedDeploymentsPath); var fileSystemPathProvider = new FileSystemPathProvider(fileSystem.Object); Assert.True(fileSystemPathProvider.TryGetDeploymentsPath(out string actualDeploymentsPath)); Assert.Equal(expectedDeploymentsPath, actualDeploymentsPath); } }
public void ReturnsEmptyPathWhenDeploymentDirectoryCreationFails() { const string deploymentsPath = "/path-0"; var mockFileSystem = new Mock <IFileSystem>(MockBehavior.Strict); var directory = new Mock <DirectoryBase>(MockBehavior.Strict); directory.Setup(d => d.Exists(deploymentsPath)).Returns(false); directory.Setup(d => d.CreateDirectory(deploymentsPath)).Throws(new IOException()); mockFileSystem.SetupGet(f => f.Directory).Returns(directory.Object); using (new MockFileSystem(mockFileSystem.Object)) { var fileSystem = new Mock <IMeshPersistentFileSystem>(MockBehavior.Strict); fileSystem.Setup(f => f.GetDeploymentsPath()).Returns(deploymentsPath); var fileSystemPathProvider = new FileSystemPathProvider(fileSystem.Object); Assert.False(fileSystemPathProvider.TryGetDeploymentsPath(out string actualDeploymentsPath)); Assert.Equal(deploymentsPath, actualDeploymentsPath); } }
/// <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")); FileSystemHelpers.DeleteDirectorySafe("/home/site/locks/deployment"); 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()); services.TryAddSingleton <ISystemEnvironment>(SystemEnvironment.Instance); services.AddSingleton <ILinuxConsumptionEnvironment, LinuxConsumptionEnvironment>(); services.AddSingleton <ILinuxConsumptionInstanceManager, LinuxConsumptionInstanceManager>(); services.AddSingleton <IFileSystemPathProvider, FileSystemPathProvider>(); services.AddSingleton <IStorageClient, StorageClient>(); KuduWebUtil.EnsureHomeEnvironmentVariable(); KuduWebUtil.EnsureSiteBitnessEnvironmentVariable(); var fileSystemPathProvider = new FileSystemPathProvider(new MeshPersistentFileSystem(SystemEnvironment.Instance, new MeshServiceClient(SystemEnvironment.Instance, new HttpClient()), new StorageClient(SystemEnvironment.Instance))); IEnvironment environment = KuduWebUtil.GetEnvironment(_hostingEnvironment, fileSystemPathProvider); _webAppRuntimeEnvironment = environment; services.AddSingleton(_ => new HttpClient()); services.AddSingleton <IMeshServiceClient>(s => { if (environment.IsOnLinuxConsumption) { var httpClient = s.GetService <HttpClient>(); var systemEnvironment = s.GetService <ISystemEnvironment>(); return(new MeshServiceClient(systemEnvironment, httpClient)); } else { return(new NullMeshServiceClient()); } }); services.AddSingleton <IMeshPersistentFileSystem>(s => { if (environment.IsOnLinuxConsumption) { var meshServiceClient = s.GetService <IMeshServiceClient>(); var storageClient = s.GetService <IStorageClient>(); var systemEnvironment = s.GetService <ISystemEnvironment>(); return(new MeshPersistentFileSystem(systemEnvironment, meshServiceClient, storageClient)); } else { return(new NullMeshPersistentFileSystem()); } }); 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); // Add middleware for Linux Consumption authentication and authorization // when KuduLIte is running in service fabric mesh services.AddLinuxConsumptionAuthentication(); services.AddLinuxConsumptionAuthorization(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 <IFileSystemPathProvider>(), 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 <IScanManager, ScanManager>(); 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; }