/Resources/Companion/AdminRole/VMManagerService/WindowsAzureVMManager.cs
C# | 2914 lines | 2394 code | 260 blank | 260 comment | 224 complexity | 04c8234ddac225de300c1450463802fe MD5 | raw file
Possible License(s): LGPL-2.0
Large files files are truncated, but you can click here to view the full file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Runtime.Serialization;
- using System.ServiceModel;
- using System.Text;
- using Microsoft.WindowsAzure.ServiceRuntime;
- using System.Xml;
- using System.ServiceModel.Syndication;
- using System.IO;
- using System.Collections.Specialized;
- using System.Diagnostics;
- using Microsoft.WindowsAzure;
- using Microsoft.WindowsAzure.StorageClient;
- using Microsoft.WindowsAzure.StorageClient.Protocol;
- using System.Runtime.Serialization.Formatters.Soap;
- using System.Net;
- using System.Xml.Linq;
- using System.Threading;
- using System.IdentityModel.Selectors;
- using System.IdentityModel.Tokens;
- using System.ServiceModel.Description;
- using System.ServiceModel.Activation;
- using Microsoft.Web.Administration;
- using System.Security.Cryptography.X509Certificates;
- using System.Net.Security;
-
- namespace WindowsAzureCompanion.VMManagerService
- {
- public class WindowsAzureVMManagerUsernamePasswordValidator : UserNamePasswordValidator
- {
- // Validate credentials
- public override void Validate(string userName, string password)
- {
- if (!(userName.Equals(RoleEnvironment.GetConfigurationSettingValue("AdminUserName"))
- && password.Equals(RoleEnvironment.GetConfigurationSettingValue("AdminPassword"))))
- {
- throw new SecurityTokenValidationException("Invalid credentials. Access denied.");
- }
- }
- }
-
- [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
- public class WindowsAzureVMManager : IVMManager
- {
- // Constants
- public static string PHPRuntimeProductID = "PHP_Runtime";
- public static string MySQLBasedDBCategory = "MySQL_BASED_DB";
- public static string MySQLCommunityServerProductID = "MySQL_Community_Server";
- public static string MariaDBProductID = "MariaDB";
- public static string LibraryFolderForPHP = "includes";
- public static string FrameworkSDKCategoryForPHP = "Frameworks and SDKs";
- public static string CustomExtensionCategoryForPHP = "PHP_Custom_Extension";
- public static string WebApplicationCategoryForPHP = "Web Applications";
- public static string MySQLCommunityServerFolder = "mysql";
- public static string MariaDBServerFolder = "mariadb";
- public static string RuntimeFolderForPHP = "php";
- public static string ExtensionsFolderForPHP = "ext";
- public static string ApplicationsFolder = "applications";
- public static string ApplicationsDownloadFolder = "downloads";
- public static string ApplicationsUnzipUtility = "UnzipUtility.vbs";
- public static string ApplicationsUntarUtility = "ExtractUtility.php";
- public static string SecondaryWebSiteName = "PHPWebSite";
- public static string AdminWebSiteNameInServiceDefinition = "Web";
-
- private string applicationsAndRuntimeResourceFolder = null;
-
- // Storage account and backup container refereences
- private CloudBlobClient blobClient = null;
- private CloudBlobContainer container = null;
-
- // Mounted Windows Azure drive
- private CloudDrive drive = null;
- private CloudPageBlob xdrivePageBlob = null;
-
- // Installation Status Collection and corresponding blob
- private NameValueCollection installationStatusCollection = null;
- private CloudBlob installationStatusBlob = null;
-
- // Cron job information (ProductID => Thread)
- private Dictionary<string, List<Thread>> cronJobs = new Dictionary<string, List<Thread>>();
-
- // Progress information
- private CloudBlob progressInformationBlob = null;
- private static object locker = new object();
-
- // Constructor for the service
- public WindowsAzureVMManager()
- {
- // Create HTTPS storage endpoint
- CloudStorageAccount storageAccount = WindowsAzureVMManager.GetStorageAccount(true);
-
- // Get backup contain reference
- blobClient = storageAccount.CreateCloudBlobClient();
- string containerName = RoleEnvironment.GetConfigurationSettingValue("PHPApplicationsBackupContainerName");
- container = blobClient.GetContainerReference(containerName);
- if (container.CreateIfNotExist())
- {
- // TODO: Finally do not provide public access
- BlobContainerPermissions containerPermissions = new BlobContainerPermissions();
- containerPermissions.PublicAccess = BlobContainerPublicAccessType.Container;
- container.SetPermissions(containerPermissions);
- }
-
- // Initialize installation status information and corresponding blob
- InitializeInstallationStatus();
-
- // Initialize progress information and corresponding blob
- InitializeProgressInformation();
- }
-
- // Initialize installation status information and corresponding blob
- private void InitializeInstallationStatus()
- {
- string blobName = RoleEnvironment.GetConfigurationSettingValue("InstallationStatusConfigFileBlob");
- installationStatusBlob = container.GetBlobReference(blobName);
- if (!WindowsAzureVMManager.BlobExists(installationStatusBlob))
- {
- // Create empty NameValueCollection and serialize to blob
- installationStatusCollection = new NameValueCollection();
- SerializeNameValueCollectionToBlob(installationStatusCollection, installationStatusBlob);
- }
- else
- {
- // Deserialize NameValueCollection to blob
- installationStatusCollection = DeserializeNameValueCollectionFromBlob(installationStatusBlob);
- }
- }
-
- // Initialize progress information and corresponding blob
- private void InitializeProgressInformation()
- {
- string blobName = RoleEnvironment.GetConfigurationSettingValue("ProgressInformationFileBlob");
- progressInformationBlob = container.GetBlobReference(blobName);
- if (!WindowsAzureVMManager.BlobExists(progressInformationBlob))
- {
- // Serialize empty NameValueCollection to blob
- NameValueCollection progressInformation = new NameValueCollection();
- SerializeNameValueCollectionToBlob(progressInformation,
- progressInformationBlob);
- }
- }
-
- // Install specified applications
- public bool InstallApplications(IDictionary<string, string> applicationsToInstall)
- {
- try
- {
- // Update progress information
- UpdateProgressInformation("Installing Platform/Applications", false);
-
- // Create a seperate thread for installing applications
- ThreadStart starter = delegate { InstallApplicationsOnAnotherThread(applicationsToInstall); };
- Thread thread = new Thread(starter);
- thread.Start();
- }
- catch (Exception ex)
- {
- UpdateProgressInformation("Unable to start application installation. Error: " + ex.Message, true);
- return false;
- }
-
- return true;
- }
-
- // Install specified applications
- private bool InstallApplicationsOnAnotherThread(IDictionary<string, string> applicationsToInstall)
- {
- try
- {
- XmlReader reader = XmlReader.Create(RoleEnvironment.GetConfigurationSettingValue("ProductListXmlFeed"));
- SyndicationFeed feed = SyndicationFeed.Load(reader);
-
- // Get list of selected products and their download URLs
- var varProducts = from item in feed.Items
- where applicationsToInstall.Keys.Contains(
- item.ElementExtensions.ReadElementExtensions<string>("productId", "http://www.w3.org/2005/Atom")[0])
- select item;
-
- // Create top level folders for PHP Runtime and Applications
- string phpRunTimeFolder = Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.RuntimeFolderForPHP);
- if (!Directory.Exists(phpRunTimeFolder))
- {
- Directory.CreateDirectory(phpRunTimeFolder);
- }
- string phpLibraryFolder = Path.Combine(phpRunTimeFolder, WindowsAzureVMManager.LibraryFolderForPHP);
- if (!Directory.Exists(phpLibraryFolder))
- {
- Directory.CreateDirectory(phpLibraryFolder);
- }
- if (!Directory.Exists(Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.ApplicationsFolder)))
- {
- Directory.CreateDirectory(Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.ApplicationsFolder));
- }
- string downloadFolder = Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.ApplicationsDownloadFolder);
- if (!Directory.Exists(downloadFolder))
- Directory.CreateDirectory(downloadFolder);
-
- // Whether to start Hosted Web Core for PHP
- bool startPHPWebSite = false;
-
- // Install Applications
- foreach (var product in varProducts)
- {
- string productId = product.ElementExtensions.ReadElementExtensions<string>("productId", "http://www.w3.org/2005/Atom")[0];
- if (installationStatusCollection.AllKeys.Contains(productId))
- {
- Trace.TraceWarning("Application {0} already installed.", productId);
- continue;
- }
-
- string installCategory = product.ElementExtensions.ReadElementExtensions<string>("installCategory", "http://www.w3.org/2005/Atom")[0];
- string[] applicationsToInstallInfo = applicationsToInstall[productId].ToString().Split(',');
- string productVersion = applicationsToInstallInfo[0];
-
- // Get product properties passed from UI
- NameValueCollection productProperties = new NameValueCollection();
- for (int i = 1; i < applicationsToInstallInfo.Length; i++)
- {
- string[] property = applicationsToInstallInfo[i].Split('=');
- productProperties.Add(property[0], property[1]);
- }
- string installPath = "/";
- if (productProperties.AllKeys.Contains("installPath"))
- {
- installPath = productProperties["installPath"];
- }
-
- // Set other readonly properties (if any)
- SyndicationElementExtension productPropertiesElementExtension =
- product.ElementExtensions.Where<SyndicationElementExtension>
- (x => x.OuterName == "productProperties").FirstOrDefault();
- if (productPropertiesElementExtension != null)
- {
- foreach (XElement productPropertyExtension in productPropertiesElementExtension.GetObject<XElement>().Elements())
- {
- XAttribute captionAttribute = productPropertyExtension.Attribute("caption");
- if (captionAttribute == null)
- {
- XAttribute nameAttribute = productPropertyExtension.Attribute("name");
- XAttribute valueAttribute = productPropertyExtension.Attribute("value");
- if ((nameAttribute != null) && (valueAttribute != null))
- {
- productProperties.Add(nameAttribute.Value, valueAttribute.Value);
- }
- }
- }
- }
-
- IInstaller installer = null;
- if (productId.Equals(WindowsAzureVMManager.PHPRuntimeProductID))
- {
- // PHP Runtime
- installer = new PHPRuntimeInstaller(
- Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.RuntimeFolderForPHP),
- downloadFolder,
- product,
- productVersion);
- startPHPWebSite = true;
- }
- else if (installCategory.Equals(WindowsAzureVMManager.MySQLBasedDBCategory))
- {
- // Allow only one MySQL based database on the VM
- if ((installationStatusCollection.AllKeys.Contains(WindowsAzureVMManager.MySQLCommunityServerProductID))
- || (installationStatusCollection.AllKeys.Contains(WindowsAzureVMManager.MariaDBProductID)))
- {
- Trace.TraceError("Only one MySQL based database can be installed and {0} is alreadyinstalled.",
- MySQLBasedDBInstaller.GetMySQLBasedDBName());
- }
- else
- {
- // Root password for MySQL based DB
- string rootPassword = "";
- if (productProperties.AllKeys.Contains("rootPassword"))
- {
- rootPassword = productProperties["rootPassword"];
- }
-
- if (productId.Equals(WindowsAzureVMManager.MySQLCommunityServerProductID))
- {
- // MySQL Community Server
- installer = new MySQLCommunityServerInstaller(
- Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.MySQLCommunityServerFolder),
- downloadFolder,
- product,
- productVersion,
- productProperties);
- }
- else if (productId.Equals(WindowsAzureVMManager.MariaDBProductID))
- {
- // MariaDB server
- installer = new MariaDBInstaller(
- Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.MariaDBServerFolder),
- downloadFolder,
- product,
- productVersion,
- productProperties);
- }
- else
- {
- Trace.TraceError("Invalid MySQL based database in applications feed");
- }
- }
- }
- else if (installCategory.Equals(WindowsAzureVMManager.CustomExtensionCategoryForPHP))
- {
- // PHP Custom extension
- installer = new PHPExtensionInstaller(
- Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.RuntimeFolderForPHP),
- downloadFolder,
- product,
- productVersion);
- startPHPWebSite = true;
- }
- else if (installCategory.Equals(WindowsAzureVMManager.FrameworkSDKCategoryForPHP))
- {
- // PHP Framework or SDK
- installer = new PHPFrameworkSDKInstaller(
- Path.Combine(
- Path.Combine(applicationsAndRuntimeResourceFolder,
- WindowsAzureVMManager.RuntimeFolderForPHP),
- WindowsAzureVMManager.LibraryFolderForPHP),
- downloadFolder,
- product,
- productVersion);
- }
- else if (installCategory.Equals(WindowsAzureVMManager.WebApplicationCategoryForPHP))
- {
- // PHP Web Application
- installer = new PHPApplicationInstaller(
- Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.ApplicationsFolder),
- installPath,
- downloadFolder,
- product,
- productVersion,
- productProperties);
- }
- else
- {
- Trace.TraceWarning("Invalid installation type.");
- continue;
- }
-
- // Install the product
- if (installer != null)
- {
- try
- {
- installer.Install();
-
- // Set product as instaleld into installedProductIds and update status in blob
- string[] installStatusInfo = null;
- if (installCategory.Equals(WindowsAzureVMManager.MySQLBasedDBCategory))
- {
- installStatusInfo = new string[] {
- DateTime.Now.ToString(),
- installPath,
- productVersion,
- productProperties["iniFileName"]
- };
- }
- else
- {
- installStatusInfo = new string[] {
- DateTime.Now.ToString(),
- installPath,
- productVersion
- };
- }
-
- // Setup cron job (if any)
- if (productProperties.AllKeys.Contains("cronJobs"))
- {
- string applicationInstallPath = Path.Combine(applicationsAndRuntimeResourceFolder,
- WindowsAzureVMManager.ApplicationsFolder);
- if (!installPath.Equals("/"))
- {
- applicationInstallPath = Path.Combine(applicationInstallPath,
- installPath.Replace("/", "\\").Trim('\\'));
- }
-
- SetupCronJobs(productId, productProperties["cronJobs"], applicationInstallPath);
- }
-
- installationStatusCollection.Add(productId, string.Join(",", installStatusInfo));
- WindowsAzureVMManager.SerializeNameValueCollectionToBlob(installationStatusCollection, installationStatusBlob);
- }
- catch (Exception ex)
- {
- UpdateProgressInformation(string.Format("Failed to install {0}. Error: {1}", product.Title.Text , ex.Message), true);
- return false;
- }
- }
-
- // Check if explicit web site restart is requested
- if (productProperties.AllKeys.Contains("restartWebSite"))
- {
- if (productProperties["restartWebSite"].ToLower().Equals("true"))
- {
- startPHPWebSite = true;
- }
- }
- }
-
- // Start or Restart Hosted Web Core if PHP Runtime or extension is installed
- if (startPHPWebSite)
- {
- // Re-configure PHP runtime
- string phpInstallFolder =
- Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.RuntimeFolderForPHP);
- PHPRuntimeInstaller.ReConfigurePHPRuntime(phpInstallFolder);
-
- // Restart PHP Web Site
- // Get latest handle to PHP web site
- ServerManager serverManager = new ServerManager();
- Site secondaryWebSite = serverManager.Sites[WindowsAzureVMManager.SecondaryWebSiteName];
- if (secondaryWebSite != null)
- {
- if (secondaryWebSite.State == ObjectState.Started)
- {
- RestartPHPWebSite();
- }
- else
- {
- StartPHPWebSite();
- }
- }
- else
- {
- StartPHPWebSite();
- }
- }
- }
- catch (Exception ex)
- {
- UpdateProgressInformation("Installation failed. Error: " + ex.Message, true);
- return false;
- }
-
- ClearProgressInformation();
- return true;
- }
-
- // Get cron job property for specified index
- private string GetCronJobProperty(string productId, int cronJobIndex)
- {
- XmlReader reader = XmlReader.Create(RoleEnvironment.GetConfigurationSettingValue("ProductListXmlFeed"));
- SyndicationFeed feed = SyndicationFeed.Load(reader);
- string[] cronJobsInfoArray = GetCronJobsProperty(feed, productId).Split(',');
- if (cronJobIndex < 0 || cronJobIndex >= cronJobsInfoArray.Length)
- {
- return null;
- }
- else
- {
- return cronJobsInfoArray[cronJobIndex];
- }
- }
-
- // Get cron job properties
- private string GetCronJobsProperty(string productId)
- {
- XmlReader reader = XmlReader.Create(RoleEnvironment.GetConfigurationSettingValue("ProductListXmlFeed"));
- SyndicationFeed feed = SyndicationFeed.Load(reader);
- return GetCronJobsProperty(feed, productId);
- }
-
- // Get cron job properties
- private string GetCronJobsProperty(SyndicationFeed feed, string productId)
- {
- SyndicationItem product = (from item in feed.Items
- where item.ElementExtensions.ReadElementExtensions<string>("productId", "http://www.w3.org/2005/Atom")[0].Equals(productId)
- select item).SingleOrDefault();
-
- // Check if cronjob is defined for this product
- SyndicationElementExtension productPropertiesElementExtension =
- product.ElementExtensions.Where<SyndicationElementExtension>
- (x => x.OuterName == "productProperties").FirstOrDefault();
- if (productPropertiesElementExtension != null)
- {
- foreach (XElement productPropertyExtension in productPropertiesElementExtension.GetObject<XElement>().Elements())
- {
- XAttribute nameAttribute = productPropertyExtension.Attribute("name");
- if (nameAttribute != null)
- {
- if (nameAttribute.Value.Equals("cronJobs"))
- {
- XAttribute valueAttribute = productPropertyExtension.Attribute("value");
- if (valueAttribute != null)
- {
- return valueAttribute.Value;
- }
- }
- }
- }
- }
-
- // Not found
- return null;
- }
-
- // Setup cron jobs for installed applications (if any)
- private void SetupCronJobsForInstalledApplications()
- {
- try
- {
- XmlReader reader = XmlReader.Create(RoleEnvironment.GetConfigurationSettingValue("ProductListXmlFeed"));
- SyndicationFeed feed = SyndicationFeed.Load(reader);
-
- // Get list of installed products
- var varProducts = from item in feed.Items
- where installationStatusCollection.AllKeys.Contains(
- item.ElementExtensions.ReadElementExtensions<string>("productId", "http://www.w3.org/2005/Atom")[0])
- select item;
- foreach (var product in varProducts)
- {
- // Check if cronjob is defined for this product
- SyndicationElementExtension productPropertiesElementExtension =
- product.ElementExtensions.Where<SyndicationElementExtension>
- (x => x.OuterName == "productProperties").FirstOrDefault();
- if (productPropertiesElementExtension != null)
- {
- foreach (XElement productPropertyExtension in productPropertiesElementExtension.GetObject<XElement>().Elements())
- {
- XAttribute nameAttribute = productPropertyExtension.Attribute("name");
- if (nameAttribute != null)
- {
- if (nameAttribute.Value.Equals("cronJobs"))
- {
- XAttribute valueAttribute = productPropertyExtension.Attribute("value");
- if (valueAttribute != null)
- {
- string productId = product.ElementExtensions.ReadElementExtensions<string>("productId", "http://www.w3.org/2005/Atom")[0];
- string[] installInfo = installationStatusCollection[productId].Split(',');
- string installPath = installInfo[1];
- string applicationInstallPath = Path.Combine(applicationsAndRuntimeResourceFolder,
- WindowsAzureVMManager.ApplicationsFolder);
- if (!installPath.Equals("/"))
- {
- applicationInstallPath = Path.Combine(applicationInstallPath,
- installPath.Replace("/", "\\").Trim('\\'));
- }
-
- SetupCronJobs(productId, valueAttribute.Value, applicationInstallPath);
- }
- }
- }
- }
- }
- }
- }
- catch (Exception ex)
- {
- Trace.TraceError("Error in cron jobs setup. Error: {0}", ex.Message);
- }
- }
-
- // Setup cron jobs
- private void SetupCronJobs(string productId, string cronJobsInfo, string applicationInstallPath)
- {
- try
- {
- if (!cronJobs.Keys.Contains(productId))
- {
- string phpInstallFolder =
- Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.RuntimeFolderForPHP);
- string phpExeFileName = Path.Combine(phpInstallFolder, "php.exe");
-
- List<Thread> threadList = new List<Thread>();
-
- string[] cronJobsInfoArray = cronJobsInfo.Split(',');
- foreach (string cronJobInfo in cronJobsInfoArray)
- {
- string[] cronJobInfoArray = cronJobInfo.Split(';');
- string cronJobInitialStatus = cronJobInfoArray[4];
-
- // Start the cron job if specified in the feed
- if (cronJobInitialStatus.ToLower().Equals("true"))
- {
- string cronJobFileName = Path.Combine(applicationInstallPath,
- cronJobInfoArray[2].Replace("/", "\\").Trim('\\'));
- int cronJobFrequencyInSecond = int.Parse(cronJobInfoArray[3]);
-
- // Create a thread for cron job
- ThreadStart starter = delegate { CronJobThreadRoutine(phpExeFileName, cronJobFileName, cronJobFrequencyInSecond); };
- Thread thread = new Thread(starter);
- threadList.Add(thread);
-
- thread.Start();
- }
- else
- {
- threadList.Add(null);
- }
- }
-
- // Add thread list to dictionary
- cronJobs.Add(productId, threadList);
- }
- }
- catch (Exception ex)
- {
- Trace.TraceError("Error in cron job {0} setup. Error: {1}", cronJobsInfo, ex.Message);
- }
- }
-
- // Cron job thread routine
- private void CronJobThreadRoutine(string processFileName, string processArguments, int cronJobFrequencyInSecond)
- {
- Trace.TraceInformation("Scheduling {0} as cron job with frequency {1} s.", processArguments, cronJobFrequencyInSecond);
-
- while (true)
- {
- try
- {
- Trace.TraceInformation("Running {0} as cron job.", processArguments);
-
- Process process = new Process();
- process.StartInfo.UseShellExecute = false;
- process.StartInfo.RedirectStandardInput = true;
- process.StartInfo.RedirectStandardOutput = true;
-
- // Output data received handler external process
- process.OutputDataReceived += new DataReceivedEventHandler(OutputDataReceivedHandler);
-
- // setting the file name and arguments
- process.StartInfo.FileName = processFileName;
- process.StartInfo.Arguments = processArguments;
- process.Start();
- // Start the asynchronous read of the output stream.
- process.BeginOutputReadLine();
-
- // Wait for cron job to exit
- process.WaitForExit();
-
- // Sleep for specified duration
- Thread.Sleep(cronJobFrequencyInSecond * 1000);
- }
- catch (ThreadAbortException)
- {
- Trace.TraceError("Cron job {0} {1} being aborted", processFileName, processArguments);
- }
- catch (Exception ex)
- {
- Trace.TraceError("Cron job {0} {1} failed: {2}", processFileName, processArguments, ex.Message);
- }
- }
- }
-
- // Stop all cron jobs
- public void StopAllCronJobs()
- {
- try
- {
- if (cronJobs.Count > 0)
- {
- Trace.TraceInformation("Stopping all cron jobs...");
- foreach (KeyValuePair<string, List<Thread>> pair in cronJobs)
- {
- List<Thread> threadList = pair.Value;
- foreach (Thread thread in threadList)
- {
- if (thread != null)
- {
- try
- {
- thread.Abort();
- thread.Join();
- }
- catch (ThreadStateException)
- {
- thread.Resume();
- }
- }
- }
-
- // Clear List
- threadList.Clear();
- }
-
- // Clear Dictionary
- cronJobs.Clear();
-
- Trace.TraceInformation("Stopped all cron jobs");
- }
- }
- catch (Exception ex)
- {
- Trace.TraceError("Error stopping all cron jobs. Error: {0}", ex.Message);
- }
- }
-
- // Get all cron jobs with their status
- public List<string> GetCronJobs()
- {
- List<string> allCronJobs = null;
- try
- {
- if (cronJobs.Count > 0)
- {
- allCronJobs = new List<string>();
-
- XmlReader reader = XmlReader.Create(RoleEnvironment.GetConfigurationSettingValue("ProductListXmlFeed"));
- SyndicationFeed feed = SyndicationFeed.Load(reader);
- foreach (KeyValuePair<string, List<Thread>> pair in cronJobs)
- {
- string productId = pair.Key;
- List<Thread> threadList = pair.Value;
- string cronJobsInfo = GetCronJobsProperty(feed, productId);
- string[] cronJobsInfoArray = cronJobsInfo.Split(',');
- List<string> cronJobsInfoStatus = new List<string>();
-
- for (int i = 0; i < cronJobsInfoArray.Length; i++)
- {
- Thread thread = threadList[i];
-
- string isJobStarted = (thread != null).ToString();
- string[] cronJobInfoArray = cronJobsInfoArray[i].Split(';');
-
- // Set actual thread staus in cronJobInfoArray
- cronJobInfoArray[4] = isJobStarted;
- cronJobsInfoStatus.Add(string.Join(";", cronJobInfoArray));
- }
-
- allCronJobs.Add(productId + "," + string.Join(",", cronJobsInfoStatus.ToArray()));
- }
- }
- }
- catch (Exception ex)
- {
- Trace.TraceError("Error in listing all cron jobs. Error: {0}", ex.Message);
- }
-
- return allCronJobs;
- }
-
- // Is Cron Job started for specified product id and cron job index?
- public bool IsCronJobStarted(string productId, int cronJobIndex)
- {
- if (cronJobs.Keys.Contains(productId))
- {
- List<Thread> threadList = cronJobs[productId];
- if (cronJobIndex >= 0 && cronJobIndex < threadList.Count)
- {
- Thread thread = threadList[cronJobIndex];
- if (thread != null)
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- // Start cron job for specified product id and cron job index
- public bool StartCronJob(string productId, int cronJobIndex)
- {
- if (cronJobs.Keys.Contains(productId))
- {
- List<Thread> threadList = cronJobs[productId];
- if (cronJobIndex >= 0 && cronJobIndex < threadList.Count)
- {
- Thread thread = threadList[cronJobIndex];
- if (thread == null)
- {
- string cronJobInfo = GetCronJobProperty(productId, cronJobIndex);
- if (string.IsNullOrEmpty(cronJobInfo))
- {
- return false;
- }
-
- string[] installInfo = installationStatusCollection[productId].Split(',');
- string installPath = installInfo[1];
- string applicationInstallPath = Path.Combine(applicationsAndRuntimeResourceFolder,
- WindowsAzureVMManager.ApplicationsFolder);
- if (!installPath.Equals("/"))
- {
- applicationInstallPath = Path.Combine(applicationInstallPath,
- installPath.Replace("/", "\\").Trim('\\'));
- }
- string[] cronJobInfoArray = cronJobInfo.Split(';');
- string cronJobFileName = Path.Combine(applicationInstallPath,
- cronJobInfoArray[2].Replace("/", "\\").Trim('\\'));
- int cronJobFrequencyInSecond = int.Parse(cronJobInfoArray[3]);
-
- // Create a thread for cron job
- string phpInstallFolder =
- Path.Combine(applicationsAndRuntimeResourceFolder, WindowsAzureVMManager.RuntimeFolderForPHP);
- string phpExeFileName = Path.Combine(phpInstallFolder, "php.exe");
- ThreadStart starter = delegate { CronJobThreadRoutine(phpExeFileName, cronJobFileName, cronJobFrequencyInSecond); };
- thread = new Thread(starter);
-
- // Replace null with new thread
- threadList[cronJobIndex] = thread;
-
- thread.Start();
- return true;
- }
- else
- {
- Trace.TraceError("Cron job already started.");
- return false;
- }
- }
- }
-
- return false;
- }
-
- // Stop cron job for specified product id and cron job index
- public bool StopCronJob(string productId, int cronJobIndex)
- {
- if (cronJobs.Keys.Contains(productId))
- {
- List<Thread> threadList = cronJobs[productId];
- if (cronJobIndex >= 0 && cronJobIndex < threadList.Count)
- {
- Thread thread = threadList[cronJobIndex];
- if (thread != null)
- {
- try
- {
- thread.Abort();
- thread.Join();
- }
- catch (ThreadStateException)
- {
- thread.Resume();
- }
-
- // Set null into threadlist
- threadList[cronJobIndex] = null;
-
- return true;
- }
- else
- {
- Trace.TraceError("Cron job already stopped.");
- return false;
- }
- }
- }
-
- return false;
- }
-
- // Restart cron job for specified product id and cron job index
- public bool RestartCronJob(string productId, int cronJobIndex)
- {
- if (cronJobs.Keys.Contains(productId))
- {
- if (StopCronJob(productId, cronJobIndex))
- {
- return StartCronJob(productId, cronJobIndex);
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
-
- // Uninstall specified applications
- public bool UninstallApplications(List<string> applications)
- {
- return false;
- }
-
- // Set as application in IIS
- public bool SetAsApplicationInIIS(string installPath, string applicationPath)
- {
- try
- {
- // Get latest handle to PHP web site
- ServerManager serverManager = new ServerManager();
- Site secondaryWebSite = serverManager.Sites[WindowsAzureVMManager.SecondaryWebSiteName];
- if (secondaryWebSite != null)
- {
- Trace.TraceInformation("Trying to set IIS Application at {0}.", applicationPath);
- Application app = secondaryWebSite.Applications.Add(installPath, applicationPath);
- if (app != null)
- {
- // Set application pool name as that of main web site
- app.ApplicationPoolName = serverManager.Sites.First().Applications.First().ApplicationPoolName;
- serverManager.CommitChanges();
- serverManager.ApplicationPools[app.ApplicationPoolName].Recycle();
- // Put some delay for IIS
- Thread.Sleep(5000);
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- catch (Exception ex)
- {
- Trace.TraceError("Unable to set application in IIS. Error: {0}.", ex.Message);
- return false;
- }
- }
-
- // Get list of Windows Azure Drive Snapshots
- public List<string> GetWindowsAzureDriveSnapshots()
- {
- List<string> snapshotUris = new List<string>();
-
- try
- {
- NameValueCollection metadata = xdrivePageBlob.Metadata;
- foreach (string key in metadata.AllKeys)
- {
- snapshotUris.Add(string.Join(",", new string[] { key, metadata[key] }));
- }
- }
- catch (Exception ex)
- {
- Trace.TraceError("Could not get list of Windows Azure Drive snapshots. Error: {0}", ex.Message);
- }
-
- return snapshotUris;
- }
-
- // Create Windows Azure Drive Snapshot
- public string CreateWindowsAzureDriveSnapshot(string snapshotComment)
- {
- string uristring = null;
- try
- {
- if (IsDriveMounted())
- {
- if (drive != null)
- {
- Uri uri = drive.Snapshot();
- uristring = uri.ToString();
-
- // Get snapshot timestamp
- string timestamp = uristring.Split('?')[1].Split('=')[1];
-
- // Get serialized status.xml
- byte[] bytesToEncode = Encoding.UTF8.GetBytes(WindowsAzureVMManager.
- SerializeNameValueCollectionToString(installationStatusCollection));
- string status = Convert.ToBase64String(bytesToEncode);
-
- // Add Uri to metadata of page blob
- string metadata = string.Join(",", new string[] { snapshotComment, uristring, status });
- xdrivePageBlob.Metadata.Add(timestamp, metadata);
-
- Trace.TraceInformation("Created Windows Azure Drive snapshot {0}", uristring);
- }
- else
- {
- Trace.TraceError("Windows Azure Drive not mounted.");
- }
- }
- else
- {
- Trace.TraceError("Windows Azure Drive not mounted.");
- }
- }
- catch (Exception ex)
- {
- Trace.TraceError(ex.Message);
- }
-
- return uristring;
- }
-
- // Promote Windows Azure Drive Snapshot
- public bool PromoteWindowsAzureDriveSnapshot(string uri)
- {
- if (string.IsNullOrEmpty(uri))
- {
- Trace.TraceError("Invalid snapshot uri {0}", uri);
- return false;
- }
-
- try
- {
- CloudBlob snapshotBlob = xdrivePageBlob.ServiceClient.GetBlobReference(uri);
- if (snapshotBlob.SnapshotTime.HasValue == false)
- {
- Trace.TraceError("Invalid snapshot uri {0}", uri);
- return false;
- }
-
- // Update progress information
- UpdateProgressInformation("Promoting Windows Azure Drive snapshot...", false);
-
- // Create a seperate thread for promoting blob snapshot
- ThreadStart starter = delegate { PromoteWindowsAzureDriveSnapshotOnAnotherThread(uri, snapshotBlob); };
- Thread thread = new Thread(starter);
- thread.Start();
- }
- catch (Exception ex)
- {
- UpdateProgressInformation("Could not promote Windows Azure Drive Snapshot. Error: " + ex.Message, true);
- return false;
- }
-
- return true;
- }
-
- // Promote Windows Azure Drive Snapshot on another thread
- private bool PromoteWindowsAzureDriveSnapshotOnAnotherThread(string uri, CloudBlob snapshotBlob)
- {
- try
- {
- // Get snapshot timestamp
- string timestamp = uri.Split('?')[1].Split('=')[1];
-
- // Get snapshot properties from metadata
- NameValueCollection metadata = new NameValueCollection(xdrivePageBlob.Metadata);
- string snapshotProperties = metadata[timestamp];
-
- // Stop all runtimes
- if (StopAllRuntimes() == false)
- {
- UpdateProgressInformation("Unbale to stop all runtime and failed to promote Windows Azure Drive Snapshot.", true);
- return false;
- }
-
- // Unmount the Windows Azure Drive
- if (IsDriveMounted())
- {
- if (drive != null)
- {
- UpdateProgressInformation("Unmounting Windows Azure Drive...", false);
- UnmountXDrive();
- UpdateProgressInformation("Unmounted Windows Azure Drive.", false);
- Thread.Sleep(5000);
- }
- }
-
- if (WindowsAzureVMManager.BlobExists(xdrivePageBlob))
- {
- // In cloud, blob snapshot delete works. It does not work in devfabric
- xdrivePageBlob.CopyFromBlob(snapshotBlob);
- }
- else
- {
- // In devfabric
- }
-
- // Restore status.xml
- UpdateProgressInformation("Restoring status.xml file...", false);
- if (string.IsNullOrEmpty(snapshotProperties))
- {
- Trace.TraceError("Could not find metadata for Windows Azure Drive snapshot with timestamp={0}.", timestamp);
- }
- else
- {
- string[] snapshotPropertiesArray = snapshotProperties.Split(',');
- if (snapshotPropertiesArray.Length != 3)
- {
- Trace.TraceError("Could not find status information in metadata for Windows Azure Drive snapshot with timestamp={0}.", timestamp);
- }
- else
- {
- string base64StatusContent = snapshotPropertiesArray[2];
- byte[] bytesToEncode = Convert.FromBase64String(base64StatusContent);
- if (bytesToEncode == null)
- {
- Trace.TraceError("Could not read status…
Large files files are truncated, but you can click here to view the full file