/* Copyright (c) Microsoft Corporation All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ namespace Microsoft.Research.Dryad { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Security.Principal; using System.Security.AccessControl; using Microsoft.Research.Dryad; internal static class ExecutionHelper { /// /// List of known files in bin directory /// private static List binFileList = new List(10); /// /// %DRYAD_HOME% bin directory where installed binaries can be found /// private static string dryadHome = Environment.GetEnvironmentVariable("DRYAD_HOME"); /// /// Lockable object used to help make this class thread safe. /// private static object initializeLock = new object(); /// /// Used to initialize known file list /// private static void InitializeBinFileList() { if (binFileList.Count == 0) { lock (initializeLock) { if (binFileList.Count == 0) { binFileList.Add("VertexHost.exe"); binFileList.Add("Microsoft.Research.Dryad.dll"); binFileList.Add("DryadLINQNativeChannels.dll"); binFileList.Add("YarnQueryNativeClusterAdapter.dll"); binFileList.Add("Microsoft.Research.Dryad.dll"); binFileList.Add("Microsoft.Research.DryadLINQ.dll"); binFileList.Add("Microsoft.Research.Dryad.Hdfs.dll"); } } } } /// /// Check for azure execution /// private static bool AzureExecution { get { string debugAzure = Environment.GetEnvironmentVariable(Constants.debugAzure); if (!String.IsNullOrEmpty(debugAzure)) { return true; } string schedulerType = Environment.GetEnvironmentVariable(Constants.schedulerTypeEnvVar); return (!String.IsNullOrEmpty(schedulerType) && schedulerType == Constants.schedulerTypeAzure); } } /// /// Copy local resources from %ccp_home%bin to working directory /// todo: Post SP2, we should run directly from %ccp_home%bin rather than performing a local copy. /// /// success = true private static bool CopyLocalBinaries() { //Console.Error.WriteLine("Copying source files from {0}", dryadHome); //DEBUG foreach (string localFile in binFileList) { // Get path to job working directory in \\hpctemp string jobFilePath = Path.Combine(ProcessPathHelper.JobPath, localFile); // Only copy files that do not already exist // Avoids overwriting files when a vertex service task fails or finishes on one node // and a new vertex service task is scheduled on the same node within the same job if (!File.Exists(jobFilePath)) { // Get path to file source in CCP_HOME\bin string sourceFilePath = Path.Combine(dryadHome, localFile); try { File.Copy(sourceFilePath, jobFilePath, true); } catch (Exception e) { Console.Error.WriteLine("[ExecutionHelper.CopyLocalResources] Exception copying '{0}' to '{1}': {2}", sourceFilePath, jobFilePath, e.Message); return false; } } } return true; } private static void GetHdfsFile(string hdfsDir, string fileName, string destFileName) { if(!hdfsDir.EndsWith("/")) { hdfsDir = hdfsDir + "/"; } var hdfsDirUri = new Uri(hdfsDir, UriKind.Absolute); var hdfsFileUri = new Uri(hdfsDirUri, fileName); var builder = new UriBuilder(); builder.Host = hdfsFileUri.DnsSafeHost; builder.Port = Constants.HdfsServiceDefaultHttpPort; builder.Path = "webhdfs/v1/" + hdfsFileUri.AbsolutePath.TrimStart('/'); builder.Query = "op=OPEN"; Console.WriteLine(builder.Uri); var wc = new WebClient(); wc.DownloadFile(builder.Uri, destFileName); } /// /// Copy the resources from staging dir to working dir /// /// list of resources supplied by dryadlinq /// success = true private static bool CopyStagedJobResources(string resources) { if (resources != null) { if (resources[0] == '@') { resources = File.ReadAllText(resources.Substring(1)); } if (resources.EndsWith(",")) { resources = resources.Substring(0, resources.Length - 1); } string[] files = resources.Split(','); DryadLogger.LogInformation("CopyStagedJobResources", string.Format("Will copy {0} resource files.", files.Length)); if (files.Length > 1) { string source = files[0]; for (int i = 1; i < files.Length; i++) { string jobFilePath = Path.Combine(ProcessPathHelper.JobPath, files[i]); // // File may already exist due to local resource copying // if (File.Exists(jobFilePath) == false) { // // If file doesn't exist today, get it from staging location // if(source.StartsWith("hdfs://", StringComparison.InvariantCultureIgnoreCase)) { // copy from HDFS DryadLogger.LogDebug("CopyStagedJobResources", string.Format( "[ExecutionHelper.CopyJobResources] Copying '{0}' to '{1}' from HDFS dir {2}", files[i], jobFilePath, source)); GetHdfsFile(source, files[i], jobFilePath); } else { string sourceFile = Path.Combine(source, files[i]); try { DryadLogger.LogDebug("CopyStagedJobResources", string.Format( "[ExecutionHelper.CopyJobResources] Copying '{0}' to '{1}'", sourceFile, jobFilePath)); File.Copy(sourceFile, jobFilePath); } catch (Exception e) { DryadLogger.LogInformation("CopyStagedJobResources", string.Format( "[ExecutionHelper.CopyJobResources] Exception copying '{0}' to '{1}': {2}", sourceFile, jobFilePath, e.Message)); return false; } } } } } else { Console.Error.WriteLine("[ExecutionHelper.CopyJobResources] invalid XC_RESOURCEFILES length = {0}", files.Length); return false; } } else { Console.Error.WriteLine("[ExecutionHelper.CopyJobResources] resources = null"); return false; } return true; } /// /// Create working directory for vertex /// /// /// public static bool InitializeForProcessExecution(int id, string resources) { try { Directory.CreateDirectory(ProcessPathHelper.ProcessPath(id)); Console.Error.WriteLine("Created directory: " + ProcessPathHelper.ProcessPath(id)); return true; } catch (Exception e) { Console.Error.WriteLine("[ExecutionHelper.InitializeForProcessExecution] Exception: {0}", e.Message); Console.Error.WriteLine(e.StackTrace); return false; } } /// /// Initialize the job directory for vertex execution /// /// list of DryadLINQ-requested resources /// success/failure public static bool InitializeForJobExecution(string resources) { try { // // Update list of known local binaries if needed // InitializeBinFileList(); ProcessPathHelper.CreateUserWorkingDirectory(); Directory.CreateDirectory(ProcessPathHelper.JobPath); // // copy any files that already live locally and may be needed for the job // bool success = CopyLocalBinaries(); // // copy any user-specified files that haven't already been copied // success &= CopyStagedJobResources(resources); return success; } catch (Exception e) { // // Write out any errors and return false on exception // Console.Error.WriteLine("[ExecutionHelper.InitializeForJobExecution] Exception: {0}", e.Message); Console.Error.WriteLine(e.StackTrace); return false; } } /// /// Checks if resource is one of the binaries already on the compute node /// /// name of resource to check public static bool IsLocalResource(string resourceName) { InitializeBinFileList(); return ((from myfile in binFileList where string.Compare(resourceName, myfile, StringComparison.OrdinalIgnoreCase) == 0 select myfile).Count() == 1); } } }