public void Dispose() { if (_cancellationToken != null && !_cancellationToken.IsCancellationRequested) { try { _cancellationToken.Cancel(); _resetEvent.Set(); } catch (Exception ex) { _logger.Error("An error occured cancelling the web deploy lease thread.", ex); } } if (_leaseId == null) { return; } try { var blob = AzureRoleEnvironment.WebDeployLeaseBlob(); blob.TryReleaseLease(_leaseId); blob.Metadata.Remove("InstanceId"); blob.SetMetadata(); _leaseId = null; } catch (Exception ex) { _logger.Error("An exception occured when attempting to clear the InstanceId from the web deploy lease metadata.", ex); } }
/// <summary> /// Packages sites that are in IIS but not in local temp storage. /// There are new sites that have been deployed to this instance using Web Deploy. /// </summary> public void PackageSitesToLocal() { _logger.DebugFormat("[IIS => Local Storage] - Site deploy times: {0}", string.Join(",", _siteDeployTimes.Select(t => t.Key + " - " + t.Value).ToArray())); using (var serverManager = new ServerManager()) { foreach (var site in serverManager.Sites.Where(s => !_sitesToExclude.Contains(s.Name))) { var siteName = site.Name.Replace("-", ".").ToLowerInvariant(); if (!site.Name.Equals(AzureRoleEnvironment.RoleWebsiteName(), StringComparison.OrdinalIgnoreCase)) { var sitePath = Path.Combine(_localSitesPath, siteName); var siteLastModifiedTime = GetFolderLastModifiedTimeUtc(sitePath); if (!_siteDeployTimes.ContainsKey(siteName)) { _siteDeployTimes.Add(siteName, siteLastModifiedTime); } _logger.DebugFormat("[IIS => Local Storage] - Site last modified time: '{0}'", siteLastModifiedTime); // If the site has been modified since the last deploy, but not within the last {SyncWait}s (otherwise it might be mid-sync) if (_siteDeployTimes[siteName] < siteLastModifiedTime && siteLastModifiedTime < DateTime.UtcNow.AddSeconds(-SyncWait)) { // Update status to deployed UpdateSyncStatus(siteName, SyncInstanceStatus.Deployed); // Ensure the temp path exists var tempSitePath = Path.Combine(_localTempPath, siteName); if (!Directory.Exists(tempSitePath)) { Directory.CreateDirectory(tempSitePath); } // Create a package of the site and move it to local temp sites var packageFile = Path.Combine(tempSitePath, siteName + ".zip"); _logger.InfoFormat("[IIS => Local Storage] - Creating a package of the site '{0}' and moving it to local temp sites '{1}'", siteName, packageFile); try { using (var deploymentObject = DeploymentManager.CreateObject(DeploymentWellKnownProvider.DirPath, sitePath)) { deploymentObject.SyncTo(DeploymentWellKnownProvider.Package, packageFile, new DeploymentBaseOptions(), new DeploymentSyncOptions()); } _logger.DebugFormat(string.Format("Calling OnSiteUpdated event for {0}...", siteName)); OnSiteUpdated(siteName); _siteDeployTimes[siteName] = DateTime.UtcNow; } catch (Exception ex) { UpdateSyncStatus(siteName, SyncInstanceStatus.Error, ex); throw; } } } } } }
public IEnumerable <SyncStatus> RetrieveSyncStatuses() { return(_table.Query .Where(s => s.PartitionKey.Equals(AzureRoleEnvironment.DeploymentId(), StringComparison.OrdinalIgnoreCase)) .ToList() .Select(s => s.ToModel()) .ToList()); }
public void Start() { _cancellationToken = new CancellationTokenSource(); _resetEvent = new ManualResetEvent(false); Task.Factory.StartNew(() => { _logger.Debug("Starting web deploy leasing thread..."); while (true) { try { var blob = AzureRoleEnvironment.WebDeployLeaseBlob(); using (var lease = new AutoRenewLease(_loggerFactory, _logLevel, blob)) { _logger.DebugFormat("Leasing thread checking...HasLease: {0}", lease.HasLease); while (lease.HasLease) { if (_leaseId != lease.LeaseId) { _logger.DebugFormat("This instance ({0}) has the lease, updating blob with the instance ID.", AzureRoleEnvironment.CurrentRoleInstanceId()); blob.Metadata["InstanceId"] = AzureRoleEnvironment.CurrentRoleInstanceId(); blob.SetMetadata(lease.LeaseId); _leaseId = lease.LeaseId; } _resetEvent.WaitOne(TimeSpan.FromSeconds(10)); if (_cancellationToken.IsCancellationRequested) { return; } } if (!_cancellationToken.IsCancellationRequested) { _leaseId = null; } } _resetEvent.WaitOne(TimeSpan.FromSeconds(30)); if (_cancellationToken.IsCancellationRequested) { return; } } catch (Exception ex) { _logger.ErrorFormat(ex, "Failed to manage lease on {0}", AzureRoleEnvironment.CurrentRoleInstanceId()); _resetEvent.WaitOne(TimeSpan.FromSeconds(30)); if (_cancellationToken.IsCancellationRequested) { return; } } } }, _cancellationToken.Token); }
public void Lease_this_instance_for_webdeploy() { _service.Start(); Thread.Sleep(TimeSpan.FromSeconds(4)); var hasWebDeployLease = AzureRoleEnvironment.HasWebDeployLease(); Assert.That(hasWebDeployLease, Is.True); }
private static string GetLocalResourcePathAndSetAccess(string localResourceName) { var resourcePath = AzureRoleEnvironment.GetLocalResourcePath(localResourceName); var localDataSec = Directory.GetAccessControl(resourcePath); localDataSec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)); Directory.SetAccessControl(resourcePath, localDataSec); return(resourcePath); }
public void Release_lease_when_requested() { _service.Start(); Thread.Sleep(TimeSpan.FromSeconds(4)); _service.Dispose(); Thread.Sleep(TimeSpan.FromSeconds(2)); var hasWebDeployLease = AzureRoleEnvironment.HasWebDeployLease(); Assert.That(hasWebDeployLease, Is.False); Assert.That(AzureRoleEnvironment.WebDeployLeaseBlob().Metadata["InstanceId"], Is.Null); }
protected override void FixtureSetup() { base.FixtureSetup(); // RoleEnvironment AzureRoleEnvironment.DeploymentId = () => "DEPLOYMENTID"; AzureRoleEnvironment.CurrentRoleInstanceId = () => "ROLEINSTANCEID"; // File Resource Paths var basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", "")); _sitePath = Path.Combine(basePath, "Sites"); _tempPath = Path.Combine(basePath, "Temp"); _configPath = Path.Combine(basePath, "Config"); _resourcesPath = Path.Combine(basePath, "_resources"); Directory.CreateDirectory(_sitePath); Directory.CreateDirectory(_tempPath); Directory.CreateDirectory(_configPath); // Website Repository var factory = new AzureStorageFactory(CloudStorageAccount.DevelopmentStorageAccount); _repo = new WebSiteRepository(factory); _webSiteTable = factory.GetTable <WebSiteRow>(typeof(WebSiteRow).Name); _bindingTable = factory.GetTable <BindingRow>(typeof(BindingRow).Name); // Clean up IIS and table storage to prepare for test using (var serverManager = new ServerManager()) { _excludedSites = new List <string>(); using (var manager = new ServerManager()) { manager.Sites.Where(s => s.Name != AzureRoleEnvironment.RoleWebsiteName()).ToList().ForEach(s => _excludedSites.Add(s.Name)); } CleanupWebsiteTest(serverManager); } // Sync Service _syncService = new SyncService( _repo, new SyncStatusRepository(factory), CloudStorageAccount.DevelopmentStorageAccount, _sitePath, _tempPath, new string[] { }, _excludedSites, () => true, new IISManager(_sitePath, _tempPath, new SyncStatusRepository(factory), new ConsoleFactory(), LoggerLevel.Debug), new ConsoleFactory(), LoggerLevel.Debug ); }
public void UpdateStatus(string webSiteName, SyncInstanceStatus status, Exception lastError = null) { var syncStatus = new SyncStatus { SiteName = webSiteName, RoleInstanceId = AzureRoleEnvironment.CurrentRoleInstanceId(), DeploymentId = AzureRoleEnvironment.DeploymentId(), Status = status, IsOnline = true, LastError = lastError }; _table.AddOrUpdate(syncStatus.ToRow()); }
internal static IContainer BuildContainer() { var storageAccount = CloudStorageAccount.Parse(AzureRoleEnvironment.GetConfigurationSettingValue("DataConnectionString")); var logFactory = new NullLogFactory(); const LoggerLevel logLevel = LoggerLevel.Off; var builder = new ContainerBuilder(); Register(builder, storageAccount, logFactory, logLevel); builder.RegisterControllers(typeof(ContainerConfig).Assembly); var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); return(container); }
private void RemoveApplications(SiteCollection iisSites, string siteName) { var adminSite = iisSites[AzureRoleEnvironment.RoleWebsiteName()]; var applicationsToRemove = from app in adminSite.Applications where app.Path.EndsWith("/test/" + siteName, StringComparison.OrdinalIgnoreCase) || app.Path.EndsWith("/cdn/" + siteName, StringComparison.OrdinalIgnoreCase) select app; _logger.InfoFormat("IISManager.Removing Test and CDN applications for site '{0}'", siteName); foreach (var app in applicationsToRemove.ToArray()) { adminSite.Applications.Remove(app); } }
public static SyncStatusRow ToRow(this SyncStatus model) { if (model == null) { return(null); } var deploymentId = string.IsNullOrWhiteSpace(model.DeploymentId) ? AzureRoleEnvironment.DeploymentId() : model.DeploymentId; var roleInstanceId = string.IsNullOrWhiteSpace(model.RoleInstanceId) ? AzureRoleEnvironment.CurrentRoleInstanceId() : model.RoleInstanceId; return(new SyncStatusRow(deploymentId, roleInstanceId, model.SiteName) { Status = model.Status.ToString(), IsOnline = model.IsOnline, LastError = model.LastError.TraceInformation() }); }
private void UpdateApplications(WebSite site, ServerManager serverManager, string siteName, string sitePath, ApplicationPool appPool) { var iisSites = serverManager.Sites; var adminSite = iisSites[AzureRoleEnvironment.RoleWebsiteName()]; var testApplication = adminSite.Applications.FirstOrDefault( app => app.Path.EndsWith("/test/" + siteName, StringComparison.OrdinalIgnoreCase)); var cdnApplication = adminSite.Applications.FirstOrDefault( app => app.Path.EndsWith("/cdn/" + siteName, StringComparison.OrdinalIgnoreCase)); if (site.EnableTestChildApplication) { if (testApplication == null) { _logger.InfoFormat("Adding Test application for site '{0}'", siteName); testApplication = adminSite.Applications.Add("/test/" + siteName, sitePath); testApplication.ApplicationPoolName = appPool.Name; } } else { if (testApplication != null) { _logger.InfoFormat("Removing Test application for site '{0}'", siteName); adminSite.Applications.Remove(testApplication); } } if (site.EnableCDNChildApplication) { if (cdnApplication == null) { _logger.InfoFormat("Adding CDN application for site '{0}'", siteName); cdnApplication = adminSite.Applications.Add("/cdn/" + siteName, Path.Combine(sitePath, "cdn")); cdnApplication.ApplicationPoolName = appPool.Name; } } else { if (cdnApplication != null) { _logger.InfoFormat("Removing CDN application for site '{0}'", siteName); adminSite.Applications.Remove(cdnApplication); } } }
public static void ConfigureRole() { // Allow multiple simultaneous HTTP request threads ServicePointManager.DefaultConnectionLimit = 12; // Allow Azure Storage to always use the latest version of a config setting CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) => { if (!AzureRoleEnvironment.IsAvailable()) { configSetter(ConfigurationManager.AppSettings[configName]); return; } configSetter(AzureRoleEnvironment.GetConfigurationSettingValue(configName)); // Apply any changes to config when the config is edited http://msdn.microsoft.com/en-us/library/windowsazure/gg494982.aspx AzureRoleEnvironment.Changed += (sender, arg) => { if (!arg.Changes.OfType <RoleEnvironmentConfigurationSettingChange>().Any(change => (change.ConfigurationSettingName == configName))) { return; } if (!configSetter(AzureRoleEnvironment.GetConfigurationSettingValue(configName))) { AzureRoleEnvironment.RequestRecycle(); } }; }); // Configure local resources var localTempPath = GetLocalResourcePathAndSetAccess(TempLocalResource); GetLocalResourcePathAndSetAccess(SitesLocalResource); GetLocalResourcePathAndSetAccess(ExecutionLocalResource); // WebDeploy creates temporary files during package creation. The default TEMP location allows for a 100MB // quota (see http://msdn.microsoft.com/en-us/library/gg465400.aspx#Y976). // For large web deploy packages, the synchronization process will raise an IO exception because the "disk is full" // unless you ensure that the TEMP/TMP target directory has sufficient space Environment.SetEnvironmentVariable("TMP", localTempPath); Environment.SetEnvironmentVariable("TEMP", localTempPath); }
public SyncService(IWebSiteRepository sitesRepository, ISyncStatusRepository syncStatusRepository, CloudStorageAccount storageAccount, string localSitesPath, string localTempPath, IEnumerable <string> directoriesToExclude, IEnumerable <string> sitesToExclude, Func <bool> syncEnabled, IISManager iisManager, ILoggerFactory loggerFactory, LoggerLevel logLevel) { _sitesRepository = sitesRepository; _syncStatusRepository = syncStatusRepository; _localSitesPath = localSitesPath; _localTempPath = localTempPath; _directoriesToExclude = directoriesToExclude; _sitesToExclude = sitesToExclude; _syncEnabled = syncEnabled; _iisManager = iisManager; _entries = new Dictionary <string, FileEntry>(); _siteDeployTimes = new Dictionary <string, DateTime>(); _logger = loggerFactory.Create(GetType(), logLevel); var sitesContainerName = AzureRoleEnvironment.GetConfigurationSettingValue(Constants.WebDeployPackagesBlobContainerKey).ToLowerInvariant(); _container = storageAccount.CreateCloudBlobClient().GetContainerReference(sitesContainerName); _container.CreateIfNotExist(); }
public void UpdateIISSitesFromTableStorage() { var allSites = _sitesRepository.RetrieveWebSitesWithBindings(); if (!AzureRoleEnvironment.IsComputeEmulatorEnvironment()) { _iisManager.UpdateSites(allSites, _sitesToExclude.ToList()); } // Cleanup for (var i = _siteDeployTimes.Count - 1; i >= 0; i--) { var siteName = _siteDeployTimes.ElementAt(i).Key; if (!allSites.Any(s => s.Name.Equals(siteName, StringComparison.OrdinalIgnoreCase))) { _siteDeployTimes.Remove(siteName); _syncStatusRepository.RemoveWebSiteStatus(siteName); var sitePath = Path.Combine(_localSitesPath, siteName); var tempSitePath = Path.Combine(_localTempPath, siteName); FilesHelper.RemoveFolder(sitePath, _logger); FilesHelper.RemoveFolder(tempSitePath, _logger); if (_entries.ContainsKey(siteName)) { // Remove blob _container.GetBlobReference(siteName).DeleteIfExists(); _container.GetBlobReference(siteName + "/" + siteName + ".zip").DeleteIfExists(); _entries.Remove(siteName); } OnSiteDeleted(siteName); } } }
public static string GetExecutionLocalResourcePath() { return(AzureRoleEnvironment.GetLocalResourcePath(ExecutionLocalResource)); }
public void UpdateSites(IEnumerable <WebSite> sites, List <string> sitesToIgnore = null) { _logger.DebugFormat("Sites list from table: {0}", string.Join(",", sites.Select(s => s.Name))); using (var serverManager = new ServerManager()) { var iisSites = serverManager.Sites; _logger.DebugFormat("Sites list from IIS: {0}", string.Join(",", iisSites.Select(s => s.Name))); // Find sites that need to be removed foreach (var iisSite in iisSites.ToArray()) { var name = iisSite.Name.ToLowerInvariant(); // Never delete "webRoleSiteName", which is the website for this web role if (!name.Equals(AzureRoleEnvironment.RoleWebsiteName(), StringComparison.OrdinalIgnoreCase) && !sites.Select(s => s.Name.ToLowerInvariant()).Contains(name) && sitesToIgnore.All(s => name != s.ToLowerInvariant())) { // Remove site _logger.InfoFormat("Removing site '{0}'", iisSite.Name); serverManager.Sites.Remove(iisSite); // Remove TEST and CDN applications RemoveApplications(iisSites, name); // Remove site path try { var sitePath = Path.Combine(_localSitesPath, iisSite.Name); var tempSitePath = Path.Combine(_tempSitesPath, iisSite.Name); FilesHelper.RemoveFolder(sitePath, _logger); FilesHelper.RemoveFolder(tempSitePath, _logger); } catch (Exception e) { _logger.Warn("Error removing site path", e); } // Remove appPool var appPool = serverManager.ApplicationPools.SingleOrDefault(ap => ap.Name.Equals(iisSite.Name, StringComparison.OrdinalIgnoreCase)); if (appPool != null) { _logger.InfoFormat("Removing app pool '{0}'", appPool.Name); serverManager.ApplicationPools.Remove(appPool); } } } try { serverManager.CommitChanges(); } catch (Exception e) { _logger.Error("Error committing changes to IIS while updating sites", e); } } foreach (var site in sites) { using (var serverManager = new ServerManager()) { var siteName = site.Name.ToLowerInvariant().Replace(" ", string.Empty); var iisSite = serverManager.Sites.SingleOrDefault(ap => ap.Name.Equals(siteName, StringComparison.OrdinalIgnoreCase)); var sitePath = Path.Combine(_localSitesPath, siteName); // Add new sites if (iisSite == null) { // Update Status _syncStatusRepository.UpdateStatus(siteName, SyncInstanceStatus.NotCreated); // Create physical path if (!Directory.Exists(sitePath)) { Directory.CreateDirectory(sitePath); } using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("AzureWebFarm.Resources.index.html")) { var fileContent = new StreamReader(stream).ReadToEnd().Replace("{WebSiteName}", siteName); File.WriteAllText(Path.Combine(sitePath, "index.html"), fileContent); } using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("AzureWebFarm.Resources.site.css")) { var fileContent = new StreamReader(stream).ReadToEnd(); File.WriteAllText(Path.Combine(sitePath, "site.css"), fileContent); } // Add web site _logger.InfoFormat("Adding site '{0}'", siteName); var defaultBinding = site.Bindings.First(); X509Certificate2 cert = null; if (!String.IsNullOrEmpty(defaultBinding.CertificateThumbprint)) { cert = GetCertificate(defaultBinding.CertificateThumbprint); } if (cert != null) { _logger.InfoFormat("Adding website '{0}' with Binding Information '{1}' and Certificate '{2}'", site.Name, defaultBinding.BindingInformation, cert.Thumbprint); iisSite = serverManager.Sites.Add( siteName, defaultBinding.BindingInformation, sitePath, cert.GetCertHash()); } else { _logger.InfoFormat("Adding website '{0}' with Binding Information '{1}'", site.Name, defaultBinding.BindingInformation); iisSite = serverManager.Sites.Add( siteName, defaultBinding.Protocol, defaultBinding.BindingInformation, sitePath); } // Create a new AppPool var appPool = serverManager.ApplicationPools.SingleOrDefault(ap => ap.Name.Equals(siteName, StringComparison.OrdinalIgnoreCase)); if (appPool == null) { _logger.InfoFormat("Adding app pool '{0}' for site '{0}'", siteName); appPool = serverManager.ApplicationPools.Add(siteName); appPool.ManagedRuntimeVersion = "v4.0"; appPool.ProcessModel.IdentityType = ProcessModelIdentityType.NetworkService; } iisSite.ApplicationDefaults.ApplicationPoolName = appPool.Name; // Update TEST and CDN applications UpdateApplications(site, serverManager, siteName, sitePath, appPool); // Update Sync Status _syncStatusRepository.UpdateStatus(siteName, SyncInstanceStatus.Created); } else { // Update TEST and CDN applications var appPool = serverManager.ApplicationPools.SingleOrDefault(ap => ap.Name.Equals(siteName, StringComparison.OrdinalIgnoreCase)); UpdateApplications(site, serverManager, siteName, sitePath, appPool); } // Find bindings that need to be removed foreach (var binding in iisSite.Bindings.ToArray()) { if (!site.Bindings.Any(b => AreEqualsBindings(binding, b))) { _logger.InfoFormat("Removing binding with protocol '{0}' from website '{1}'", binding.Protocol, site); iisSite.Bindings.Remove(binding); } } // Add new bindings foreach (var binding in site.Bindings) { var iisBinding = iisSite.Bindings.SingleOrDefault(b => AreEqualsBindings(b, binding)); if (iisBinding == null) { X509Certificate2 cert = null; if (!String.IsNullOrEmpty(binding.CertificateThumbprint)) { cert = GetCertificate(binding.CertificateThumbprint); } if (cert != null) { _logger.InfoFormat("Adding Binding '{0}' for website '{1}' with Binding Information '{2}' and Certificate '{3}'", binding.Id, site.Name, binding.BindingInformation, cert.Thumbprint); iisSite.Bindings.Add(binding.BindingInformation, cert.GetCertHash(), StoreName.My.ToString()); } else { _logger.InfoFormat("Adding Binding '{0}' for WebSite '{1}' with Binding Information '{2}'", binding.Id, site.Name, binding.BindingInformation); iisSite.Bindings.Add(binding.BindingInformation, binding.Protocol); } } } try { _logger.DebugFormat("Committing updates to IIS for site '{0}'", site.Name); serverManager.CommitChanges(); } catch (Exception e) { _syncStatusRepository.UpdateStatus(siteName, SyncInstanceStatus.Error, e); _logger.ErrorFormat(e, "Error committing changes for site '{0}'", site.Name); } } } }
protected void Page_Load(object sender, EventArgs e) { Response.StatusCode = AzureRoleEnvironment.HasWebDeployLease() ? (int)HttpStatusCode.OK : (int)HttpStatusCode.ServiceUnavailable; }
public void Dispose() { foreach (var syncStatus in _syncStatusRepository.RetrieveSyncStatusByInstanceId(AzureRoleEnvironment.CurrentRoleInstanceId())) { syncStatus.IsOnline = false; _syncStatusRepository.Update(syncStatus); } }
public void Not_have_a_webdeploy_lease_initially() { Assert.That(AzureRoleEnvironment.HasWebDeployLease(), Is.False); }
public static string GetSitesLocalResourcePath() { return(AzureRoleEnvironment.GetLocalResourcePath(SitesLocalResource)); }