http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-common-project/hadoop-common/src/main/winutils/task.c ---------------------------------------------------------------------- diff --git a/hadoop-common-project/hadoop-common/src/main/winutils/task.c b/hadoop-common-project/hadoop-common/src/main/winutils/task.c index 783f162..f0fc19a 100644 --- a/hadoop-common-project/hadoop-common/src/main/winutils/task.c +++ b/hadoop-common-project/hadoop-common/src/main/winutils/task.c @@ -18,29 +18,32 @@ #include "winutils.h" #include <errno.h> #include <psapi.h> -#include <malloc.h> +#include <malloc.h> +#include <authz.h> +#include <sddl.h> #define PSAPI_VERSION 1 #pragma comment(lib, "psapi.lib") -#define ERROR_TASK_NOT_ALIVE 1 +#define NM_WSCE_IMPERSONATE_ALLOWED L"yarn.nodemanager.windows-secure-container-executor.impersonate.allowed" +#define NM_WSCE_IMPERSONATE_DENIED L"yarn.nodemanager.windows-secure-container-executor.impersonate.denied" -// This exit code for killed processes is compatible with Unix, where a killed -// process exits with 128 + signal. For SIGKILL, this would be 128 + 9 = 137. -#define KILLED_PROCESS_EXIT_CODE 137 +// The S4U impersonation access check mask. Arbitrary value (we use 1 for the service access check) +#define SERVICE_IMPERSONATE_MASK 0x00000002 + + +// Name for tracking this logon process when registering with LSA +static const char *LOGON_PROCESS_NAME="Hadoop Container Executor"; +// Name for token source, must be less or eq to TOKEN_SOURCE_LENGTH (currently 8) chars +static const char *TOKEN_SOURCE_NAME = "HadoopEx"; -// Name for tracking this logon process when registering with LSA -static const char *LOGON_PROCESS_NAME="Hadoop Container Executor"; -// Name for token source, must be less or eq to TOKEN_SOURCE_LENGTH (currently 8) chars -static const char *TOKEN_SOURCE_NAME = "HadoopEx"; - // List of different task related command line options supported by // winutils. typedef enum TaskCommandOptionType { TaskInvalid, TaskCreate, - TaskCreateAsUser, + TaskCreateAsUser, TaskIsAlive, TaskKill, TaskProcessList @@ -93,53 +96,524 @@ static BOOL ParseCommandLine(__in int argc, } } - if (argc >= 6) { - if (wcscmp(argv[1], L"createAsUser") == 0) - { - *command = TaskCreateAsUser; - return TRUE; - } - } - + if (argc >= 6) { + if (wcscmp(argv[1], L"createAsUser") == 0) + { + *command = TaskCreateAsUser; + return TRUE; + } + } + return FALSE; } + //---------------------------------------------------------------------------- -// Function: CreateTaskImpl +// Function: BuildImpersonateSecurityDescriptor +// +// Description: +// Builds the security descriptor for the S4U impersonation permissions +// This describes what users can be impersonated and what not +// +// Returns: +// ERROR_SUCCESS: On success +// GetLastError: otherwise +// +DWORD BuildImpersonateSecurityDescriptor(__out PSECURITY_DESCRIPTOR* ppSD) { + DWORD dwError = ERROR_SUCCESS; + size_t countAllowed = 0; + PSID* allowedSids = NULL; + size_t countDenied = 0; + PSID* deniedSids = NULL; + LPCWSTR value = NULL; + WCHAR** tokens = NULL; + size_t len = 0; + size_t count = 0; + int crt = 0; + PSECURITY_DESCRIPTOR pSD = NULL; + + dwError = GetConfigValue(wsceConfigRelativePath, NM_WSCE_IMPERSONATE_ALLOWED, &len, &value); + if (dwError) { + ReportErrorCode(L"GetConfigValue:1", dwError); + goto done; + } + + if (0 == len) { + dwError = ERROR_BAD_CONFIGURATION; + ReportErrorCode(L"GetConfigValue:2", dwError); + goto done; + } + + dwError = SplitStringIgnoreSpaceW(len, value, L',', &count, &tokens); + if (dwError) { + ReportErrorCode(L"SplitStringIgnoreSpaceW:1", dwError); + goto done; + } + + allowedSids = LocalAlloc(LPTR, sizeof(PSID) * count); + if (NULL == allowedSids) { + dwError = GetLastError(); + ReportErrorCode(L"LocalAlloc:1", dwError); + goto done; + } + + for(crt = 0; crt < count; ++crt) { + dwError = GetSidFromAcctNameW(tokens[crt], &allowedSids[crt]); + if (dwError) { + ReportErrorCode(L"GetSidFromAcctNameW:1", dwError); + goto done; + } + } + countAllowed = count; + + LocalFree(tokens); + tokens = NULL; + + LocalFree(value); + value = NULL; + + dwError = GetConfigValue(wsceConfigRelativePath, NM_WSCE_IMPERSONATE_DENIED, &len, &value); + if (dwError) { + ReportErrorCode(L"GetConfigValue:3", dwError); + goto done; + } + + if (0 != len) { + dwError = SplitStringIgnoreSpaceW(len, value, L',', &count, &tokens); + if (dwError) { + ReportErrorCode(L"SplitStringIgnoreSpaceW:2", dwError); + goto done; + } + + deniedSids = LocalAlloc(LPTR, sizeof(PSID) * count); + if (NULL == allowedSids) { + dwError = GetLastError(); + ReportErrorCode(L"LocalAlloc:2", dwError); + goto done; + } + + for(crt = 0; crt < count; ++crt) { + dwError = GetSidFromAcctNameW(tokens[crt], &deniedSids[crt]); + if (dwError) { + ReportErrorCode(L"GetSidFromAcctNameW:2", dwError); + goto done; + } + } + countDenied = count; + } + + dwError = BuildServiceSecurityDescriptor( + SERVICE_IMPERSONATE_MASK, + countAllowed, allowedSids, + countDenied, deniedSids, + NULL, + &pSD); + + if (dwError) { + ReportErrorCode(L"BuildServiceSecurityDescriptor", dwError); + goto done; + } + + *ppSD = pSD; + pSD = NULL; + +done: + if (pSD) LocalFree(pSD); + if (tokens) LocalFree(tokens); + if (allowedSids) LocalFree(allowedSids); + if (deniedSids) LocalFree(deniedSids); + return dwError; +} + +//---------------------------------------------------------------------------- +// Function: AddNodeManagerAndUserACEsToObject +// +// Description: +// Adds ACEs to grant NM and user the provided access mask over a given handle +// +// Returns: +// ERROR_SUCCESS: on success +// +DWORD AddNodeManagerAndUserACEsToObject( + __in HANDLE hObject, + __in LPWSTR user, + __in ACCESS_MASK accessMask) { + + DWORD dwError = ERROR_SUCCESS; + int countTokens = 0; + size_t len = 0; + LPCWSTR value = NULL; + WCHAR** tokens = NULL; + int crt = 0; + PACL pDacl = NULL; + PSECURITY_DESCRIPTOR psdProcess = NULL; + LPSTR lpszOldDacl = NULL, lpszNewDacl = NULL; + ULONG daclLen = 0; + PACL pNewDacl = NULL; + ACL_SIZE_INFORMATION si; + DWORD dwNewAclSize = 0; + PACE_HEADER pTempAce = NULL; + BYTE sidTemp[SECURITY_MAX_SID_SIZE]; + DWORD cbSid = SECURITY_MAX_SID_SIZE; + PSID tokenSid = NULL; + // These hard-coded SIDs are allways added + WELL_KNOWN_SID_TYPE forcesSidTypes[] = { + WinLocalSystemSid, + WinBuiltinAdministratorsSid}; + BOOL logSDs = IsDebuggerPresent(); // Check only once to avoid attach-while-running + + + dwError = GetSecurityInfo(hObject, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + &pDacl, + NULL, + &psdProcess); + if (dwError) { + ReportErrorCode(L"GetSecurityInfo", dwError); + goto done; + } + + // This is debug only output for troubleshooting + if (logSDs) { + if (!ConvertSecurityDescriptorToStringSecurityDescriptor( + psdProcess, + SDDL_REVISION_1, + DACL_SECURITY_INFORMATION, + &lpszOldDacl, + &daclLen)) { + dwError = GetLastError(); + ReportErrorCode(L"ConvertSecurityDescriptorToStringSecurityDescriptor", dwError); + goto done; + } + } + + ZeroMemory(&si, sizeof(si)); + if (!GetAclInformation(pDacl, &si, sizeof(si), AclSizeInformation)) { + dwError = GetLastError(); + ReportErrorCode(L"GetAclInformation", dwError); + goto done; + } + + dwError = GetConfigValue(wsceConfigRelativePath, NM_WSCE_ALLOWED, &len, &value); + if (ERROR_SUCCESS != dwError) { + ReportErrorCode(L"GetConfigValue", dwError); + goto done; + } + + if (0 == len) { + dwError = ERROR_BAD_CONFIGURATION; + ReportErrorCode(L"GetConfigValue", dwError); + goto done; + } + + dwError = SplitStringIgnoreSpaceW(len, value, L',', &countTokens, &tokens); + if (ERROR_SUCCESS != dwError) { + ReportErrorCode(L"SplitStringIgnoreSpaceW", dwError); + goto done; + } + + // We're gonna add 1 ACE for each token found, +1 for user and +1 for each forcesSidTypes[] + // ACCESS_ALLOWED_ACE struct contains the first DWORD of the SID + // + dwNewAclSize = si.AclBytesInUse + + (countTokens + 1 + sizeof(forcesSidTypes)/sizeof(forcesSidTypes[0])) * + (sizeof(ACCESS_ALLOWED_ACE) + SECURITY_MAX_SID_SIZE - sizeof(DWORD)); + + pNewDacl = (PSID) LocalAlloc(LPTR, dwNewAclSize); + if (!pNewDacl) { + dwError = ERROR_OUTOFMEMORY; + ReportErrorCode(L"LocalAlloc", dwError); + goto done; + } + + if (!InitializeAcl(pNewDacl, dwNewAclSize, ACL_REVISION)) { + dwError = ERROR_OUTOFMEMORY; + ReportErrorCode(L"InitializeAcl", dwError); + goto done; + } + + // Copy over old ACEs + for (crt = 0; crt < si.AceCount; ++crt) { + if (!GetAce(pDacl, crt, &pTempAce)) { + dwError = ERROR_OUTOFMEMORY; + ReportErrorCode(L"InitializeAcl", dwError); + goto done; + } + if (!AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pTempAce, pTempAce->AceSize)) { + dwError = ERROR_OUTOFMEMORY; + ReportErrorCode(L"InitializeAcl", dwError); + goto done; + } + } + + // Add the configured allowed SIDs + for (crt = 0; crt < countTokens; ++crt) { + dwError = GetSidFromAcctNameW(tokens[crt], &tokenSid); + if (ERROR_SUCCESS != dwError) { + ReportErrorCode(L"GetSidFromAcctNameW", dwError); + goto done; + } + if (!AddAccessAllowedAceEx( + pNewDacl, + ACL_REVISION_DS, + CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, + PROCESS_ALL_ACCESS, + tokenSid)) { + dwError = GetLastError(); + ReportErrorCode(L"AddAccessAllowedAceEx:1", dwError); + goto done; + } + LocalFree(tokenSid); + tokenSid = NULL; + } + + // add the forced SIDs ACE + for (crt = 0; crt < sizeof(forcesSidTypes)/sizeof(forcesSidTypes[0]); ++crt) { + cbSid = SECURITY_MAX_SID_SIZE; + if (!CreateWellKnownSid(forcesSidTypes[crt], NULL, &sidTemp, &cbSid)) { + dwError = GetLastError(); + ReportErrorCode(L"CreateWellKnownSid", dwError); + goto done; + } + if (!AddAccessAllowedAceEx( + pNewDacl, + ACL_REVISION_DS, + CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, + accessMask, + (PSID) sidTemp)) { + dwError = GetLastError(); + ReportErrorCode(L"AddAccessAllowedAceEx:2", dwError); + goto done; + } + } + + // add the user ACE + dwError = GetSidFromAcctNameW(user, &tokenSid); + if (ERROR_SUCCESS != dwError) { + ReportErrorCode(L"GetSidFromAcctNameW:user", dwError); + goto done; + } + + if (!AddAccessAllowedAceEx( + pNewDacl, + ACL_REVISION_DS, + CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, + PROCESS_ALL_ACCESS, + tokenSid)) { + dwError = GetLastError(); + ReportErrorCode(L"AddAccessAllowedAceEx:3", dwError); + goto done; + } + + LocalFree(tokenSid); + tokenSid = NULL; + + dwError = SetSecurityInfo(hObject, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + pNewDacl, + NULL); + if (dwError) { + ReportErrorCode(L"SetSecurityInfo", dwError); + goto done; + } + + // This is debug only output for troubleshooting + if (logSDs) { + dwError = GetSecurityInfo(hObject, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + &pDacl, + NULL, + &psdProcess); + if (dwError) { + ReportErrorCode(L"GetSecurityInfo:2", dwError); + goto done; + } + + if (!ConvertSecurityDescriptorToStringSecurityDescriptor( + psdProcess, + SDDL_REVISION_1, + DACL_SECURITY_INFORMATION, + &lpszNewDacl, + &daclLen)) { + dwError = GetLastError(); + ReportErrorCode(L"ConvertSecurityDescriptorToStringSecurityDescriptor:2", dwError); + goto done; + } + + LogDebugMessage(L"Old DACL: %s\nNew DACL: %s\n", lpszOldDacl, lpszNewDacl); + } + +done: + if (tokenSid) LocalFree(tokenSid); + if (pNewDacl) LocalFree(pNewDacl); + if (lpszOldDacl) LocalFree(lpszOldDacl); + if (lpszNewDacl) LocalFree(lpszNewDacl); + if (psdProcess) LocalFree(psdProcess); + + return dwError; +} + +//---------------------------------------------------------------------------- +// Function: ValidateImpersonateAccessCheck +// +// Description: +// Performs the access check for S4U impersonation +// +// Returns: +// ERROR_SUCCESS: On success +// ERROR_ACCESS_DENIED, GetLastError: otherwise +// +DWORD ValidateImpersonateAccessCheck(__in HANDLE logonHandle) { + DWORD dwError = ERROR_SUCCESS; + PSECURITY_DESCRIPTOR pSD = NULL; + LUID luidUnused; + AUTHZ_ACCESS_REQUEST request; + AUTHZ_ACCESS_REPLY reply; + DWORD authError = ERROR_SUCCESS; + DWORD saclResult = 0; + ACCESS_MASK grantedMask = 0; + AUTHZ_RESOURCE_MANAGER_HANDLE hManager = NULL; + AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzToken = NULL; + + ZeroMemory(&luidUnused, sizeof(luidUnused)); + ZeroMemory(&request, sizeof(request)); + ZeroMemory(&reply, sizeof(reply)); + + dwError = BuildImpersonateSecurityDescriptor(&pSD); + if (dwError) { + ReportErrorCode(L"BuildImpersonateSecurityDescriptor", dwError); + goto done; + } + + request.DesiredAccess = MAXIMUM_ALLOWED; + reply.Error = &authError; + reply.SaclEvaluationResults = &saclResult; + reply.ResultListLength = 1; + reply.GrantedAccessMask = &grantedMask; + + if (!AuthzInitializeResourceManager( + AUTHZ_RM_FLAG_NO_AUDIT, + NULL, // pfnAccessCheck + NULL, // pfnComputeDynamicGroups + NULL, // pfnFreeDynamicGroups + NULL, // szResourceManagerName + &hManager)) { + dwError = GetLastError(); + ReportErrorCode(L"AuthzInitializeResourceManager", dwError); + goto done; + } + + if (!AuthzInitializeContextFromToken( + 0, + logonHandle, + hManager, + NULL, // expiration time + luidUnused, // not used + NULL, // callback args + &hAuthzToken)) { + dwError = GetLastError(); + ReportErrorCode(L"AuthzInitializeContextFromToken", dwError); + goto done; + } + + if (!AuthzAccessCheck( + 0, + hAuthzToken, + &request, + NULL, // AuditEvent + pSD, + NULL, // OptionalSecurityDescriptorArray + 0, // OptionalSecurityDescriptorCount + &reply, + NULL // phAccessCheckResults + )) { + dwError = GetLastError(); + ReportErrorCode(L"AuthzAccessCheck", dwError); + goto done; + } + + LogDebugMessage(L"AutzAccessCheck: Error:%d sacl:%d access:%d\n", + authError, saclResult, grantedMask); + + if (authError != ERROR_SUCCESS) { + ReportErrorCode(L"AuthzAccessCheck:REPLY:1", authError); + dwError = authError; + } + else if (!(grantedMask & SERVICE_IMPERSONATE_MASK)) { + ReportErrorCode(L"AuthzAccessCheck:REPLY:2", ERROR_ACCESS_DENIED); + dwError = ERROR_ACCESS_DENIED; + } + +done: + if (hAuthzToken) AuthzFreeContext(hAuthzToken); + if (hManager) AuthzFreeResourceManager(hManager); + if (pSD) LocalFree(pSD); + return dwError; +} + +//---------------------------------------------------------------------------- +// Function: CreateTaskImpl // // Description: // Creates a task via a jobobject. Outputs the // appropriate information to stdout on success, or stderr on failure. -// logonHandle may be NULL, in this case the current logon will be utilized for the -// created process +// logonHandle may be NULL, in this case the current logon will be utilized for the +// created process // // Returns: // ERROR_SUCCESS: On success // GetLastError: otherwise -DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PWSTR cmdLine) +DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PCWSTR cmdLine, + __in LPCWSTR userName) { - DWORD dwErrorCode = ERROR_SUCCESS; + DWORD dwErrorCode = ERROR_SUCCESS; DWORD exitCode = EXIT_FAILURE; - DWORD currDirCnt = 0; + DWORD currDirCnt = 0; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE jobObject = NULL; JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; - void * envBlock = NULL; - BOOL createProcessResult = FALSE; - - wchar_t* curr_dir = NULL; - FILE *stream = NULL; + void * envBlock = NULL; + WCHAR secureJobNameBuffer[MAX_PATH]; + LPCWSTR secureJobName = jobObjName; + + wchar_t* curr_dir = NULL; + FILE *stream = NULL; + + if (NULL != logonHandle) { + dwErrorCode = ValidateImpersonateAccessCheck(logonHandle); + if (dwErrorCode) { + ReportErrorCode(L"ValidateImpersonateAccessCheck", dwErrorCode); + return dwErrorCode; + } + + dwErrorCode = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer); + if (dwErrorCode) { + ReportErrorCode(L"GetSecureJobObjectName", dwErrorCode); + return dwErrorCode; + } + secureJobName = secureJobNameBuffer; + } // Create un-inheritable job object handle and set job object to terminate // when last handle is closed. So winutils.exe invocation has the only open // job object handle. Exit of winutils.exe ensures termination of job object. // Either a clean exit of winutils or crash or external termination. - jobObject = CreateJobObject(NULL, jobObjName); - dwErrorCode = GetLastError(); - if(jobObject == NULL || dwErrorCode == ERROR_ALREADY_EXISTS) + jobObject = CreateJobObject(NULL, secureJobName); + dwErrorCode = GetLastError(); + if(jobObject == NULL || dwErrorCode == ERROR_ALREADY_EXISTS) { - return dwErrorCode; + ReportErrorCode(L"CreateJobObject", dwErrorCode); + return dwErrorCode; } jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if(SetInformationJobObject(jobObject, @@ -147,102 +621,143 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PW &jeli, sizeof(jeli)) == 0) { - dwErrorCode = GetLastError(); + dwErrorCode = GetLastError(); + ReportErrorCode(L"SetInformationJobObject", dwErrorCode); CloseHandle(jobObject); - return dwErrorCode; - } + return dwErrorCode; + } + + dwErrorCode = AddNodeManagerAndUserACEsToObject(jobObject, userName, JOB_OBJECT_ALL_ACCESS); + if (dwErrorCode) { + ReportErrorCode(L"AddNodeManagerAndUserACEsToObject", dwErrorCode); + CloseHandle(jobObject); + return dwErrorCode; + } if(AssignProcessToJobObject(jobObject, GetCurrentProcess()) == 0) { - dwErrorCode = GetLastError(); + dwErrorCode = GetLastError(); + ReportErrorCode(L"AssignProcessToJobObject", dwErrorCode); CloseHandle(jobObject); - return dwErrorCode; + return dwErrorCode; } // the child JVM uses this env var to send the task OS process identifier // to the TaskTracker. We pass the job object name. if(SetEnvironmentVariable(L"JVM_PID", jobObjName) == 0) { - dwErrorCode = GetLastError(); - // We have to explictly Terminate, passing in the error code - // simply closing the job would kill our own process with success exit status - TerminateJobObject(jobObject, dwErrorCode); - return dwErrorCode; + dwErrorCode = GetLastError(); + ReportErrorCode(L"SetEnvironmentVariable", dwErrorCode); + // We have to explictly Terminate, passing in the error code + // simply closing the job would kill our own process with success exit status + TerminateJobObject(jobObject, dwErrorCode); + return dwErrorCode; } ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); - if( logonHandle != NULL ) { - // create user environment for this logon - if(!CreateEnvironmentBlock(&envBlock, - logonHandle, - TRUE )) { - dwErrorCode = GetLastError(); - // We have to explictly Terminate, passing in the error code - // simply closing the job would kill our own process with success exit status - TerminateJobObject(jobObject, dwErrorCode); - return dwErrorCode; - } - } - - // Get the required buffer size first - currDirCnt = GetCurrentDirectory(0, NULL); - if (0 < currDirCnt) { - curr_dir = (wchar_t*) alloca(currDirCnt * sizeof(wchar_t)); - assert(curr_dir); - currDirCnt = GetCurrentDirectory(currDirCnt, curr_dir); - } - - if (0 == currDirCnt) { - dwErrorCode = GetLastError(); - // We have to explictly Terminate, passing in the error code - // simply closing the job would kill our own process with success exit status - TerminateJobObject(jobObject, dwErrorCode); - return dwErrorCode; - } - - if (logonHandle == NULL) { - createProcessResult = CreateProcess( - NULL, // ApplicationName - cmdLine, // command line - NULL, // process security attributes - NULL, // thread security attributes - TRUE, // inherit handles - 0, // creation flags - NULL, // environment - curr_dir, // current directory - &si, // startup info - &pi); // process info - } - else { - createProcessResult = CreateProcessAsUser( - logonHandle, // logon token handle - NULL, // Application handle - cmdLine, // command line - NULL, // process security attributes - NULL, // thread security attributes - FALSE, // inherit handles - CREATE_UNICODE_ENVIRONMENT, // creation flags - envBlock, // environment - curr_dir, // current directory - &si, // startup info - &pi); // process info - } - - if (FALSE == createProcessResult) { - dwErrorCode = GetLastError(); - if( envBlock != NULL ) { - DestroyEnvironmentBlock( envBlock ); - envBlock = NULL; - } - // We have to explictly Terminate, passing in the error code - // simply closing the job would kill our own process with success exit status - TerminateJobObject(jobObject, dwErrorCode); - - // This is tehnically dead code, we cannot reach this condition - return dwErrorCode; + if( logonHandle != NULL ) { + // create user environment for this logon + if(!CreateEnvironmentBlock(&envBlock, + logonHandle, + TRUE )) { + dwErrorCode = GetLastError(); + ReportErrorCode(L"CreateEnvironmentBlock", dwErrorCode); + // We have to explictly Terminate, passing in the error code + // simply closing the job would kill our own process with success exit status + TerminateJobObject(jobObject, dwErrorCode); + return dwErrorCode; + } + } + + // Get the required buffer size first + currDirCnt = GetCurrentDirectory(0, NULL); + if (0 < currDirCnt) { + curr_dir = (wchar_t*) alloca(currDirCnt * sizeof(wchar_t)); + assert(curr_dir); + currDirCnt = GetCurrentDirectory(currDirCnt, curr_dir); + } + + if (0 == currDirCnt) { + dwErrorCode = GetLastError(); + ReportErrorCode(L"GetCurrentDirectory", dwErrorCode); + // We have to explictly Terminate, passing in the error code + // simply closing the job would kill our own process with success exit status + TerminateJobObject(jobObject, dwErrorCode); + return dwErrorCode; + } + + dwErrorCode = ERROR_SUCCESS; + + if (logonHandle == NULL) { + if (!CreateProcess( + NULL, // ApplicationName + cmdLine, // command line + NULL, // process security attributes + NULL, // thread security attributes + TRUE, // inherit handles + 0, // creation flags + NULL, // environment + curr_dir, // current directory + &si, // startup info + &pi)) { // process info + dwErrorCode = GetLastError(); + ReportErrorCode(L"CreateProcess", dwErrorCode); + } + goto create_process_done; + } + + // From here on is the secure S4U implementation for CreateProcessAsUser + + // We desire to grant process access to NM so that it can interogate process status + // and resource utilization. Passing in a security descriptor though results in the + // S4U privilege checks being done against that SD and CreateProcessAsUser fails. + // So instead we create the process suspended and then we add the desired ACEs. + // + if (!CreateProcessAsUser( + logonHandle, // logon token handle + NULL, // Application handle + cmdLine, // command line + NULL, // process security attributes + NULL, // thread security attributes + FALSE, // inherit handles + CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED, // creation flags + envBlock, // environment + curr_dir, // current directory + &si, // startup info + &pi)) { // process info + dwErrorCode = GetLastError(); + ReportErrorCode(L"CreateProcessAsUser", dwErrorCode); + goto create_process_done; + } + + dwErrorCode = AddNodeManagerAndUserACEsToObject(pi.hProcess, userName, PROCESS_ALL_ACCESS); + if (dwErrorCode) { + ReportErrorCode(L"AddNodeManagerAndUserACEsToObject", dwErrorCode); + goto create_process_done; + } + + if (-1 == ResumeThread(pi.hThread)) { + dwErrorCode = GetLastError(); + ReportErrorCode(L"ResumeThread", dwErrorCode); + goto create_process_done; + } + +create_process_done: + + if (dwErrorCode) { + if( envBlock != NULL ) { + DestroyEnvironmentBlock( envBlock ); + envBlock = NULL; + } + // We have to explictly Terminate, passing in the error code + // simply closing the job would kill our own process with success exit status + TerminateJobObject(jobObject, dwErrorCode); + + // This is tehnically dead code, we cannot reach this condition + return dwErrorCode; } CloseHandle(pi.hThread); @@ -251,15 +766,15 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PW WaitForSingleObject( pi.hProcess, INFINITE ); if(GetExitCodeProcess(pi.hProcess, &exitCode) == 0) { - dwErrorCode = GetLastError(); + dwErrorCode = GetLastError(); } CloseHandle( pi.hProcess ); - if( envBlock != NULL ) { - DestroyEnvironmentBlock( envBlock ); - envBlock = NULL; - } - + if( envBlock != NULL ) { + DestroyEnvironmentBlock( envBlock ); + envBlock = NULL; + } + // Terminate job object so that all spawned processes are also killed. // This is needed because once this process closes the handle to the job // object and none of the spawned objects have the handle open (via @@ -267,134 +782,133 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PW // program (say winutils task kill) to terminate this job object via its name. if(TerminateJobObject(jobObject, exitCode) == 0) { - dwErrorCode = GetLastError(); + dwErrorCode = GetLastError(); } - // comes here only on failure of TerminateJobObject + // comes here only on failure of TerminateJobObject CloseHandle(jobObject); - if(dwErrorCode != ERROR_SUCCESS) + if(dwErrorCode != ERROR_SUCCESS) { - return dwErrorCode; + return dwErrorCode; } return exitCode; } //---------------------------------------------------------------------------- -// Function: CreateTask -// -// Description: -// Creates a task via a jobobject. Outputs the -// appropriate information to stdout on success, or stderr on failure. -// -// Returns: -// ERROR_SUCCESS: On success -// GetLastError: otherwise -DWORD CreateTask(__in PCWSTR jobObjName,__in PWSTR cmdLine) -{ - // call with null logon in order to create tasks utilizing the current logon - return CreateTaskImpl( NULL, jobObjName, cmdLine ); -} -//---------------------------------------------------------------------------- -// Function: CreateTask -// -// Description: -// Creates a task via a jobobject. Outputs the -// appropriate information to stdout on success, or stderr on failure. -// -// Returns: -// ERROR_SUCCESS: On success -// GetLastError: otherwise -DWORD CreateTaskAsUser(__in PCWSTR jobObjName,__in PWSTR user, __in PWSTR pidFilePath, __in PWSTR cmdLine) -{ - DWORD err = ERROR_SUCCESS; - DWORD exitCode = EXIT_FAILURE; - ULONG authnPkgId; - HANDLE lsaHandle = INVALID_HANDLE_VALUE; - PROFILEINFO pi; - BOOL profileIsLoaded = FALSE; - FILE* pidFile = NULL; - - DWORD retLen = 0; - HANDLE logonHandle = NULL; - - err = EnablePrivilege(SE_TCB_NAME); - if( err != ERROR_SUCCESS ) { - fwprintf(stdout, L"INFO: The user does not have SE_TCB_NAME.\n"); - goto done; - } - err = EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); - if( err != ERROR_SUCCESS ) { - fwprintf(stdout, L"INFO: The user does not have SE_ASSIGNPRIMARYTOKEN_NAME.\n"); - goto done; - } - err = EnablePrivilege(SE_INCREASE_QUOTA_NAME); - if( err != ERROR_SUCCESS ) { - fwprintf(stdout, L"INFO: The user does not have SE_INCREASE_QUOTA_NAME.\n"); - goto done; - } - err = EnablePrivilege(SE_RESTORE_NAME); - if( err != ERROR_SUCCESS ) { - fwprintf(stdout, L"INFO: The user does not have SE_RESTORE_NAME.\n"); - goto done; - } - - err = RegisterWithLsa(LOGON_PROCESS_NAME ,&lsaHandle); - if( err != ERROR_SUCCESS ) goto done; - - err = LookupKerberosAuthenticationPackageId( lsaHandle, &authnPkgId ); - if( err != ERROR_SUCCESS ) goto done; - - err = CreateLogonForUser(lsaHandle, - LOGON_PROCESS_NAME, - TOKEN_SOURCE_NAME, - authnPkgId, - user, - &logonHandle); - if( err != ERROR_SUCCESS ) goto done; - - err = LoadUserProfileForLogon(logonHandle, &pi); - if( err != ERROR_SUCCESS ) goto done; - profileIsLoaded = TRUE; - - // Create the PID file - - if (!(pidFile = _wfopen(pidFilePath, "w"))) { - err = GetLastError(); - goto done; - } - - if (0 > fprintf_s(pidFile, "%ls", jobObjName)) { - err = GetLastError(); - } - - fclose(pidFile); - - if (err != ERROR_SUCCESS) { - goto done; - } - - err = CreateTaskImpl(logonHandle, jobObjName, cmdLine); - -done: - if( profileIsLoaded ) { - UnloadProfileForLogon( logonHandle, &pi ); - profileIsLoaded = FALSE; - } - if( logonHandle != NULL ) { - CloseHandle(logonHandle); - } - - if (INVALID_HANDLE_VALUE != lsaHandle) { - UnregisterWithLsa(lsaHandle); - } - - return err; -} - - -//---------------------------------------------------------------------------- -// Function: IsTaskAlive +// Function: CreateTask +// +// Description: +// Creates a task via a jobobject. Outputs the +// appropriate information to stdout on success, or stderr on failure. +// +// Returns: +// ERROR_SUCCESS: On success +// GetLastError: otherwise +DWORD CreateTask(__in PCWSTR jobObjName,__in PWSTR cmdLine) +{ + // call with null logon in order to create tasks utilizing the current logon + return CreateTaskImpl( NULL, jobObjName, cmdLine, NULL); +} + +//---------------------------------------------------------------------------- +// Function: CreateTaskAsUser +// +// Description: +// Creates a task via a jobobject. Outputs the +// appropriate information to stdout on success, or stderr on failure. +// +// Returns: +// ERROR_SUCCESS: On success +// GetLastError: otherwise +DWORD CreateTaskAsUser(__in PCWSTR jobObjName, + __in PCWSTR user, __in PCWSTR pidFilePath, __in PCWSTR cmdLine) +{ + DWORD err = ERROR_SUCCESS; + DWORD exitCode = EXIT_FAILURE; + ULONG authnPkgId; + HANDLE lsaHandle = INVALID_HANDLE_VALUE; + PROFILEINFO pi; + BOOL profileIsLoaded = FALSE; + FILE* pidFile = NULL; + DWORD retLen = 0; + HANDLE logonHandle = NULL; + + err = EnableImpersonatePrivileges(); + if( err != ERROR_SUCCESS ) { + ReportErrorCode(L"EnableImpersonatePrivileges", err); + goto done; + } + + err = RegisterWithLsa(LOGON_PROCESS_NAME ,&lsaHandle); + if( err != ERROR_SUCCESS ) { + ReportErrorCode(L"RegisterWithLsa", err); + goto done; + } + + err = LookupKerberosAuthenticationPackageId( lsaHandle, &authnPkgId ); + if( err != ERROR_SUCCESS ) { + ReportErrorCode(L"LookupKerberosAuthenticationPackageId", err); + goto done; + } + + err = CreateLogonTokenForUser(lsaHandle, + LOGON_PROCESS_NAME, + TOKEN_SOURCE_NAME, + authnPkgId, + user, + &logonHandle); + if( err != ERROR_SUCCESS ) { + ReportErrorCode(L"CreateLogonTokenForUser", err); + goto done; + } + + err = LoadUserProfileForLogon(logonHandle, &pi); + if( err != ERROR_SUCCESS ) { + ReportErrorCode(L"LoadUserProfileForLogon", err); + goto done; + } + profileIsLoaded = TRUE; + + // Create the PID file + + if (!(pidFile = _wfopen(pidFilePath, "w"))) { + err = GetLastError(); + ReportErrorCode(L"_wfopen:pidFilePath", err); + goto done; + } + + if (0 > fprintf_s(pidFile, "%ls", jobObjName)) { + err = GetLastError(); + } + + fclose(pidFile); + + if (err != ERROR_SUCCESS) { + ReportErrorCode(L"fprintf_s:pidFilePath", err); + goto done; + } + + err = CreateTaskImpl(logonHandle, jobObjName, cmdLine, user); + +done: + if( profileIsLoaded ) { + UnloadProfileForLogon( logonHandle, &pi ); + profileIsLoaded = FALSE; + } + if( logonHandle != NULL ) { + CloseHandle(logonHandle); + } + + if (INVALID_HANDLE_VALUE != lsaHandle) { + UnregisterWithLsa(lsaHandle); + } + + return err; +} + +//---------------------------------------------------------------------------- +// Function: IsTaskAlive // // Description: // Checks if a task is alive via a jobobject. Outputs the @@ -403,15 +917,32 @@ done: // Returns: // ERROR_SUCCESS: On success // GetLastError: otherwise -DWORD IsTaskAlive(const WCHAR* jobObjName, int* isAlive, int* procsInJob) +DWORD IsTaskAlive(const WCHAR* jobObjName, int* isAlive, int* procsInJob) { PJOBOBJECT_BASIC_PROCESS_ID_LIST procList; HANDLE jobObject = NULL; int numProcs = 100; + WCHAR secureJobNameBuffer[MAX_PATH]; *isAlive = FALSE; jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName); + if(jobObject == NULL) + { + // Try Global\... + DWORD err = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer); + if (err) { + ReportErrorCode(L"GetSecureJobObjectName", err); + return err; + } + jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, secureJobNameBuffer); + } + + if(jobObject == NULL) + { + DWORD err = GetLastError(); + return err; + } if(jobObject == NULL) { @@ -454,40 +985,7 @@ DWORD IsTaskAlive(const WCHAR* jobObjName, int* isAlive, int* procsInJob) } //---------------------------------------------------------------------------- -// Function: KillTask -// -// Description: -// Kills a task via a jobobject. Outputs the -// appropriate information to stdout on success, or stderr on failure. -// -// Returns: -// ERROR_SUCCESS: On success -// GetLastError: otherwise -DWORD KillTask(PCWSTR jobObjName) -{ - HANDLE jobObject = OpenJobObject(JOB_OBJECT_TERMINATE, FALSE, jobObjName); - if(jobObject == NULL) - { - DWORD err = GetLastError(); - if(err == ERROR_FILE_NOT_FOUND) - { - // job object does not exist. assume its not alive - return ERROR_SUCCESS; - } - return err; - } - - if(TerminateJobObject(jobObject, KILLED_PROCESS_EXIT_CODE) == 0) - { - return GetLastError(); - } - CloseHandle(jobObject); - - return ERROR_SUCCESS; -} - -//---------------------------------------------------------------------------- -// Function: PrintTaskProcessList +// Function: PrintTaskProcessList // // Description: // Prints resource usage of all processes in the task jobobject @@ -495,12 +993,26 @@ DWORD KillTask(PCWSTR jobObjName) // Returns: // ERROR_SUCCESS: On success // GetLastError: otherwise -DWORD PrintTaskProcessList(const WCHAR* jobObjName) +DWORD PrintTaskProcessList(const WCHAR* jobObjName) { DWORD i; PJOBOBJECT_BASIC_PROCESS_ID_LIST procList; int numProcs = 100; - HANDLE jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName); + WCHAR secureJobNameBuffer[MAX_PATH]; + HANDLE jobObject = NULL; + + jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName); + if(jobObject == NULL) + { + // Try Global\... + DWORD err = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer); + if (err) { + ReportErrorCode(L"GetSecureJobObjectName", err); + return err; + } + jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, secureJobNameBuffer); + } + if(jobObject == NULL) { DWORD err = GetLastError(); @@ -579,21 +1091,21 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[]) { DWORD dwErrorCode = ERROR_SUCCESS; TaskCommandOption command = TaskInvalid; - wchar_t* cmdLine = NULL; - wchar_t buffer[16*1024] = L""; // 32K max command line - size_t charCountBufferLeft = sizeof (buffer)/sizeof(wchar_t); - int crtArgIndex = 0; - size_t argLen = 0; - size_t wscatErr = 0; - wchar_t* insertHere = NULL; - - enum { - ARGC_JOBOBJECTNAME = 2, - ARGC_USERNAME, - ARGC_PIDFILE, - ARGC_COMMAND, - ARGC_COMMAND_ARGS - }; + wchar_t* cmdLine = NULL; + wchar_t buffer[16*1024] = L""; // 32K max command line + size_t charCountBufferLeft = sizeof(buffer)/sizeof(wchar_t); + int crtArgIndex = 0; + size_t argLen = 0; + size_t wscatErr = 0; + wchar_t* insertHere = NULL; + + enum { + ARGC_JOBOBJECTNAME = 2, + ARGC_USERNAME, + ARGC_PIDFILE, + ARGC_COMMAND, + ARGC_COMMAND_ARGS + }; if (!ParseCommandLine(argc, argv, &command)) { dwErrorCode = ERROR_INVALID_COMMAND_LINE; @@ -607,57 +1119,57 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[]) { // Create the task jobobject // - dwErrorCode = CreateTask(argv[2], argv[3]); - if (dwErrorCode != ERROR_SUCCESS) - { - ReportErrorCode(L"CreateTask", dwErrorCode); - goto TaskExit; - } - } else if (command == TaskCreateAsUser) - { - // Create the task jobobject as a domain user - // createAsUser accepts an open list of arguments. All arguments after the command are - // to be passed as argumrnts to the command itself.Here we're concatenating all - // arguments after the command into a single arg entry. - // - cmdLine = argv[ARGC_COMMAND]; - if (argc > ARGC_COMMAND_ARGS) { - crtArgIndex = ARGC_COMMAND; - insertHere = buffer; - while (crtArgIndex < argc) { - argLen = wcslen(argv[crtArgIndex]); - wscatErr = wcscat_s(insertHere, charCountBufferLeft, argv[crtArgIndex]); - switch (wscatErr) { - case 0: - // 0 means success; - break; - case EINVAL: - dwErrorCode = ERROR_INVALID_PARAMETER; - goto TaskExit; - case ERANGE: - dwErrorCode = ERROR_INSUFFICIENT_BUFFER; - goto TaskExit; - default: - // This case is not MSDN documented. - dwErrorCode = ERROR_GEN_FAILURE; - goto TaskExit; - } - insertHere += argLen; - charCountBufferLeft -= argLen; - insertHere[0] = L' '; - insertHere += 1; - charCountBufferLeft -= 1; - insertHere[0] = 0; - ++crtArgIndex; - } - cmdLine = buffer; - } - - dwErrorCode = CreateTaskAsUser( - argv[ARGC_JOBOBJECTNAME], argv[ARGC_USERNAME], argv[ARGC_PIDFILE], cmdLine); + dwErrorCode = CreateTask(argv[2], argv[3]); + if (dwErrorCode != ERROR_SUCCESS) + { + ReportErrorCode(L"CreateTask", dwErrorCode); + goto TaskExit; + } + } else if (command == TaskCreateAsUser) + { + // Create the task jobobject as a domain user + // createAsUser accepts an open list of arguments. All arguments after the command are + // to be passed as argumrnts to the command itself.Here we're concatenating all + // arguments after the command into a single arg entry. + // + cmdLine = argv[ARGC_COMMAND]; + if (argc > ARGC_COMMAND_ARGS) { + crtArgIndex = ARGC_COMMAND; + insertHere = buffer; + while (crtArgIndex < argc) { + argLen = wcslen(argv[crtArgIndex]); + wscatErr = wcscat_s(insertHere, charCountBufferLeft, argv[crtArgIndex]); + switch (wscatErr) { + case 0: + // 0 means success; + break; + case EINVAL: + dwErrorCode = ERROR_INVALID_PARAMETER; + goto TaskExit; + case ERANGE: + dwErrorCode = ERROR_INSUFFICIENT_BUFFER; + goto TaskExit; + default: + // This case is not MSDN documented. + dwErrorCode = ERROR_GEN_FAILURE; + goto TaskExit; + } + insertHere += argLen; + charCountBufferLeft -= argLen; + insertHere[0] = L' '; + insertHere += 1; + charCountBufferLeft -= 1; + insertHere[0] = 0; + ++crtArgIndex; + } + cmdLine = buffer; + } + + dwErrorCode = CreateTaskAsUser( + argv[ARGC_JOBOBJECTNAME], argv[ARGC_USERNAME], argv[ARGC_PIDFILE], cmdLine); if (dwErrorCode != ERROR_SUCCESS) { - ReportErrorCode(L"CreateTaskAsUser", dwErrorCode); + ReportErrorCode(L"CreateTaskAsUser", dwErrorCode); goto TaskExit; } } else if (command == TaskIsAlive) @@ -666,10 +1178,10 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[]) // int isAlive; int numProcs; - dwErrorCode = IsTaskAlive(argv[2], &isAlive, &numProcs); + dwErrorCode = IsTaskAlive(argv[2], &isAlive, &numProcs); if (dwErrorCode != ERROR_SUCCESS) { - ReportErrorCode(L"IsTaskAlive", dwErrorCode); + ReportErrorCode(L"IsTaskAlive", dwErrorCode); goto TaskExit; } @@ -681,27 +1193,27 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[]) else { dwErrorCode = ERROR_TASK_NOT_ALIVE; - ReportErrorCode(L"IsTaskAlive returned false", dwErrorCode); + ReportErrorCode(L"IsTaskAlive returned false", dwErrorCode); goto TaskExit; } } else if (command == TaskKill) { // Check if task jobobject // - dwErrorCode = KillTask(argv[2]); + dwErrorCode = KillTask(argv[2]); if (dwErrorCode != ERROR_SUCCESS) { - ReportErrorCode(L"KillTask", dwErrorCode); + ReportErrorCode(L"KillTask", dwErrorCode); goto TaskExit; } } else if (command == TaskProcessList) { // Check if task jobobject // - dwErrorCode = PrintTaskProcessList(argv[2]); + dwErrorCode = PrintTaskProcessList(argv[2]); if (dwErrorCode != ERROR_SUCCESS) { - ReportErrorCode(L"PrintTaskProcessList", dwErrorCode); + ReportErrorCode(L"PrintTaskProcessList", dwErrorCode); goto TaskExit; } } else @@ -712,6 +1224,7 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[]) } TaskExit: + ReportErrorCode(L"TaskExit:", dwErrorCode); return dwErrorCode; } @@ -722,12 +1235,12 @@ void TaskUsage() // ProcessTree.isSetsidSupported() fwprintf(stdout, L"\ Usage: task create [TASKNAME] [COMMAND_LINE] |\n\ - task createAsUser [TASKNAME] [USERNAME] [PIDFILE] [COMMAND_LINE] |\n\ + task createAsUser [TASKNAME] [USERNAME] [PIDFILE] [COMMAND_LINE] |\n\ task isAlive [TASKNAME] |\n\ task kill [TASKNAME]\n\ task processList [TASKNAME]\n\ Creates a new task jobobject with taskname\n\ - Creates a new task jobobject with taskname as the user provided\n\ + Creates a new task jobobject with taskname as the user provided\n\ Checks if task jobobject is alive\n\ Kills task jobobject\n\ Prints to stdout a list of processes in the task\n\
http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-common-project/hadoop-common/src/main/winutils/winutils.mc ---------------------------------------------------------------------- diff --git a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.mc b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.mc new file mode 100644 index 0000000..2add064 --- /dev/null +++ b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.mc @@ -0,0 +1,64 @@ +;/* +; * Licensed to the Apache Software Foundation (ASF) under one +; * or more contributor license agreements. See the NOTICE file +; * distributed with this work for additional information +; * regarding copyright ownership. The ASF licenses this file +; * to you 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 +; * +; * Unless required by applicable law or agreed to in writing, software +; * distributed under the License is distributed on an "AS IS" BASIS, +; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; * See the License for the specific language governing permissions and +; * limitations under the License. +; */ + +; // winutils.mc + +; // EventLog messages for Hadoop winutils service. + + +LanguageNames=(English=0x409:MSG00409) + + +; // The following are the categories of events. + +MessageIdTypedef=WORD + +MessageId=0x1 +SymbolicName=SERVICE_CATEGORY +Language=English +Service Events +. + +MessageId=0x2 +SymbolicName=LOG_CATEGORY +Language=English +Task Events +. + +; // The following are the message definitions. + +MessageIdTypedef=DWORD + +MessageId=0x80 +SymbolicName=MSG_CHECK_ERROR +Language=English +%1. Error %2: %3. +. + +MessageId=0x100 +SymbolicName=MSG_RPC_SERVICE_HAS_STARTED +Language=English +The LPC server is listenning. +. + +MessageId=0x200 +SymbolicName=MSG_RPC_SERVICE_HAS_STOPPED +Language=English +The LPC server has stopped listenning. +. + http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln ---------------------------------------------------------------------- diff --git a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln index d4e019e..d2784b8 100644 --- a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln +++ b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln @@ -26,26 +26,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwinutils", "libwinutils. EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|Win32.ActiveCfg = Debug|x64 - {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|Win32.Build.0 = Debug|x64 - {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|x64.ActiveCfg = Debug|x64 - {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|x64.Build.0 = Debug|x64 - {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Release|Win32.ActiveCfg = Release|Win32 - {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Release|Win32.Build.0 = Release|Win32 + {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|x64.ActiveCfg = Release|x64 + {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|x64.Build.0 = Release|x64 {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Release|x64.ActiveCfg = Release|x64 {D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Release|x64.Build.0 = Release|x64 - {12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|Win32.ActiveCfg = Debug|x64 - {12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|Win32.Build.0 = Debug|x64 - {12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|x64.ActiveCfg = Debug|x64 - {12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|x64.Build.0 = Debug|x64 - {12131AA7-902E-4A6D-9CE3-043261D22A12}.Release|Win32.ActiveCfg = Release|Win32 - {12131AA7-902E-4A6D-9CE3-043261D22A12}.Release|Win32.Build.0 = Release|Win32 + {12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|x64.ActiveCfg = Release|x64 + {12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|x64.Build.0 = Release|x64 {12131AA7-902E-4A6D-9CE3-043261D22A12}.Release|x64.ActiveCfg = Release|x64 {12131AA7-902E-4A6D-9CE3-043261D22A12}.Release|x64.Build.0 = Release|x64 EndGlobalSection http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj ---------------------------------------------------------------------- diff --git a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj index 5b9a195..d736084 100644 --- a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj +++ b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj @@ -19,18 +19,10 @@ <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Debug|Win32"> - <Configuration>Debug</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> <ProjectConfiguration Include="Debug|x64"> <Configuration>Debug</Configuration> <Platform>x64</Platform> </ProjectConfiguration> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> <ProjectConfiguration Include="Release|x64"> <Configuration>Release</Configuration> <Platform>x64</Platform> @@ -42,22 +34,11 @@ <RootNamespace>winutils</RootNamespace> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> @@ -67,15 +48,9 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> @@ -83,57 +58,32 @@ <PropertyGroup> <IncludePath>include;$(IncludePath)</IncludePath> </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <LinkIncremental>true</LinkIncremental> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <LinkIncremental>true</LinkIncremental> - <OutDir /> - <IntDir>..\..\..\target\winutils\$(Configuration)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LinkIncremental>false</LinkIncremental> - </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <LinkIncremental>false</LinkIncremental> - <IntDir>..\..\..\target\winutils\$(Platform)\$(Configuration)\</IntDir> - <OutDir>..\..\..\target\bin\</OutDir> </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <ClCompile> - <PrecompiledHeader> - </PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - </Link> - </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <PrecompiledHeader> </PrecompiledHeader> <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_CONSOLE;_DEBUG;_UNICODE;UNICODE;WSCE_CONFIG_DIR=$(WsceConfigDir);WSCE_CONFIG_FILE=$(WsceConfigFile);%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link> <SubSystem>Console</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> </Link> </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <WarningLevel>Level3</WarningLevel> <PrecompiledHeader> </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> + <!-- <Optimization>MaxSpeed</Optimization> --> + <Optimization>Disabled</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_CONSOLE;NDEBUG;_UNICODE;UNICODE;WSCE_CONFIG_DIR=$(WsceConfigDir);WSCE_CONFIG_FILE=$(WsceConfigFile);%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -142,24 +92,40 @@ <OptimizeReferences>true</OptimizeReferences> </Link> </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ItemDefinitionGroup> <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(IntermediateOutputPath)</AdditionalIncludeDirectories> </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - </Link> + <CustomBuildStep> + <Message>Compiling Messages</Message> + <Command>mc.exe $(TargetName).mc -z $(TargetName)_msg -r $(IntermediateOutputPath) -h $(IntermediateOutputPath) -U</Command> + <Outputs>$(IntermediateOutputPath)$(TargetName)_msg.rc;$(IntermediateOutputPath)$(TargetName)_msg.h</Outputs> + </CustomBuildStep> + <Midl> + <ApplicationConfigurationMode>true</ApplicationConfigurationMode> + <TargetEnvironment>X64</TargetEnvironment> + <OutputDirectory>$(IntermediateOutputPath)</OutputDirectory> + <GenerateStublessProxies>true</GenerateStublessProxies> + <ValidateAllParameters>true</ValidateAllParameters> + <WarnAsError>true</WarnAsError> + <WarningLevel>2</WarningLevel> + </Midl> </ItemDefinitionGroup> + <PropertyGroup> + <CustomBuildAfterTargets>Midl</CustomBuildAfterTargets> + <CustomBuildBeforeTargets>ClCompile,ResourceCompile</CustomBuildBeforeTargets> + </PropertyGroup> + <ItemGroup> + <Midl Include="hadoopwinutilsvc.idl" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="$(IntermediateOutputPath)$(TargetName)_msg.rc" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="$(IntermediateOutputPath)\hadoopwinutilsvc_s.c" /> + </ItemGroup> <ItemGroup> + <ClCompile Include="service.c" /> <ClCompile Include="readlink.c" /> <ClCompile Include="symlink.c" /> <ClCompile Include="systeminfo.c" /> @@ -179,4 +145,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java ---------------------------------------------------------------------- diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java index 2f8b84d..1e2d16e 100644 --- a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java @@ -296,7 +296,7 @@ public class ProcessTree { return false; } catch (IOException ioe) { LOG.warn("Error executing shell command " - + Arrays.toString(shexec.getExecString()) + ioe); + + shexec.toString() + ioe); return false; } return (shexec.getExitCode() == 0 ? true : false); @@ -321,7 +321,7 @@ public class ProcessTree { return false; } catch (IOException ioe) { LOG.warn("Error executing shell command " - + Arrays.toString(shexec.getExecString()) + ioe); + + shexec.toString() + ioe); return false; } return (shexec.getExitCode() == 0 ? true : false); http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-yarn-project/CHANGES.txt ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index df22042..d44e1ca 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -117,6 +117,9 @@ Release 2.6.0 - UNRELEASED YARN-1972. Added a secure container-executor for Windows. (Remus Rusanu via vinodkv) + YARN-2198. Remove the need to run NodeManager as privileged account for + Windows Secure Container Executor. (Remus Rusanu via jianhe) + IMPROVEMENTS YARN-2242. Improve exception information on AM launch crashes. (Li Lu http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java index f5e63ba..3b866d3 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java @@ -79,19 +79,23 @@ public abstract class ContainerExecutor implements Configurable { public abstract void init() throws IOException; /** - * On Windows the ContainerLaunch creates a temporary empty jar to workaround the CLASSPATH length - * In a secure cluster this jar must be localized so that the container has access to it + * On Windows the ContainerLaunch creates a temporary special jar manifest of + * other jars to workaround the CLASSPATH length. In a secure cluster this + * jar must be localized so that the container has access to it. * This function localizes on-demand the jar. * * @param classPathJar * @param owner * @throws IOException */ - public void localizeClasspathJar(Path classPathJar, String owner) throws IOException { - // For the default container this is a no-op - // The WindowsSecureContainerExecutor overrides this + public Path localizeClasspathJar(Path classPathJar, Path pwd, String owner) + throws IOException { + // Non-secure executor simply use the classpath created + // in the NM fprivate folder + return classPathJar; } - + + /** * Prepare the environment for containers in this application to execute. * For $x in local.dirs @@ -105,14 +109,13 @@ public abstract class ContainerExecutor implements Configurable { * @param appId id of the application * @param nmPrivateContainerTokens path to localized credentials, rsrc by NM * @param nmAddr RPC address to contact NM - * @param localDirs nm-local-dirs - * @param logDirs nm-log-dirs + * @param dirsHandler NM local dirs service, for nm-local-dirs and nm-log-dirs * @throws IOException For most application init failures * @throws InterruptedException If application init thread is halted by NM */ public abstract void startLocalizer(Path nmPrivateContainerTokens, InetSocketAddress nmAddr, String user, String appId, String locId, - List<String> localDirs, List<String> logDirs) + LocalDirsHandlerService dirsHandler) throws IOException, InterruptedException; @@ -132,8 +135,8 @@ public abstract class ContainerExecutor implements Configurable { */ public abstract int launchContainer(Container container, Path nmPrivateContainerScriptPath, Path nmPrivateTokensPath, - String user, String appId, Path containerWorkDir, List<String> localDirs, - List<String> logDirs) throws IOException; + String user, String appId, Path containerWorkDir, + List<String> localDirs, List<String> logDirs) throws IOException; public abstract boolean signalContainer(String user, String pid, Signal signal) http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java index 76603ca..3e212bf 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java @@ -19,6 +19,7 @@ package org.apache.hadoop.yarn.server.nodemanager; import com.google.common.base.Optional; + import static org.apache.hadoop.fs.CreateFlag.CREATE; import static org.apache.hadoop.fs.CreateFlag.OVERWRITE; @@ -32,9 +33,11 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.Random; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileContext; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.UnsupportedFileSystemException; @@ -42,6 +45,7 @@ import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.util.Shell; import org.apache.hadoop.util.Shell.ExitCodeException; +import org.apache.hadoop.util.Shell.CommandExecutor; import org.apache.hadoop.util.Shell.ShellCommandExecutor; import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.yarn.api.records.ContainerId; @@ -92,13 +96,16 @@ public class DefaultContainerExecutor extends ContainerExecutor { @Override public synchronized void startLocalizer(Path nmPrivateContainerTokensPath, InetSocketAddress nmAddr, String user, String appId, String locId, - List<String> localDirs, List<String> logDirs) + LocalDirsHandlerService dirsHandler) throws IOException, InterruptedException { + List<String> localDirs = dirsHandler.getLocalDirs(); + List<String> logDirs = dirsHandler.getLogDirs(); + ContainerLocalizer localizer = new ContainerLocalizer(lfs, user, appId, locId, getPaths(localDirs), RecordFactoryProvider.getRecordFactory(getConf())); - + createUserLocalDirs(localDirs, user); createUserCacheDirs(localDirs, user); createAppDirs(localDirs, user, appId); @@ -120,9 +127,9 @@ public class DefaultContainerExecutor extends ContainerExecutor { @Override public int launchContainer(Container container, Path nmPrivateContainerScriptPath, Path nmPrivateTokensPath, - String userName, String appId, Path containerWorkDir, + String user, String appId, Path containerWorkDir, List<String> localDirs, List<String> logDirs) throws IOException { - + FsPermission dirPerm = new FsPermission(APPDIR_PERM); ContainerId containerId = container.getContainerId(); @@ -134,29 +141,30 @@ public class DefaultContainerExecutor extends ContainerExecutor { getApplicationId()); for (String sLocalDir : localDirs) { Path usersdir = new Path(sLocalDir, ContainerLocalizer.USERCACHE); - Path userdir = new Path(usersdir, userName); + Path userdir = new Path(usersdir, user); Path appCacheDir = new Path(userdir, ContainerLocalizer.APPCACHE); Path appDir = new Path(appCacheDir, appIdStr); Path containerDir = new Path(appDir, containerIdStr); - createDir(containerDir, dirPerm, true, userName); + createDir(containerDir, dirPerm, true, user); } // Create the container log-dirs on all disks - createContainerLogDirs(appIdStr, containerIdStr, logDirs, userName); + createContainerLogDirs(appIdStr, containerIdStr, logDirs, user); Path tmpDir = new Path(containerWorkDir, YarnConfiguration.DEFAULT_CONTAINER_TEMP_DIR); - createDir(tmpDir, dirPerm, false, userName); + createDir(tmpDir, dirPerm, false, user); - // copy launch script to work dir - Path launchDst = - new Path(containerWorkDir, ContainerLaunch.CONTAINER_SCRIPT); - copyFile(nmPrivateContainerScriptPath, launchDst, userName); // copy container tokens to work dir Path tokenDst = new Path(containerWorkDir, ContainerLaunch.FINAL_CONTAINER_TOKENS_FILE); - copyFile(nmPrivateTokensPath, tokenDst, userName); + copyFile(nmPrivateTokensPath, tokenDst, user); + + // copy launch script to work dir + Path launchDst = + new Path(containerWorkDir, ContainerLaunch.CONTAINER_SCRIPT); + copyFile(nmPrivateContainerScriptPath, launchDst, user); // Create new local launch wrapper script LocalWrapperScriptBuilder sb = getLocalWrapperScriptBuilder( @@ -181,23 +189,19 @@ public class DefaultContainerExecutor extends ContainerExecutor { + " was marked as inactive. Returning terminated error"); return ExitCode.TERMINATED.getExitCode(); } - + // create log dir under app // fork script - ShellCommandExecutor shExec = null; + Shell.CommandExecutor shExec = null; try { - setScriptExecutable(launchDst, userName); - setScriptExecutable(sb.getWrapperScriptPath(), userName); - - // Setup command to run - String[] command = getRunCommand(sb.getWrapperScriptPath().toString(), - containerIdStr, userName, pidFile, this.getConf()); + setScriptExecutable(launchDst, user); + setScriptExecutable(sb.getWrapperScriptPath(), user); - LOG.info("launchContainer: " + Arrays.toString(command)); - shExec = new ShellCommandExecutor( - command, + shExec = buildCommandExecutor(sb.getWrapperScriptPath().toString(), + containerIdStr, user, pidFile, new File(containerWorkDir.toUri().getPath()), - container.getLaunchContext().getEnvironment()); // sanitized env + container.getLaunchContext().getEnvironment()); + if (isContainerActive(containerId)) { shExec.execute(); } @@ -242,11 +246,26 @@ public class DefaultContainerExecutor extends ContainerExecutor { } return exitCode; } finally { - ; // + if (shExec != null) shExec.close(); } return 0; } + protected CommandExecutor buildCommandExecutor(String wrapperScriptPath, + String containerIdStr, String user, Path pidFile, File wordDir, + Map<String, String> environment) + throws IOException { + + String[] command = getRunCommand(wrapperScriptPath, + containerIdStr, user, pidFile, this.getConf()); + + LOG.info("launchContainer: " + Arrays.toString(command)); + return new ShellCommandExecutor( + command, + wordDir, + environment); + } + protected LocalWrapperScriptBuilder getLocalWrapperScriptBuilder( String containerIdStr, Path containerWorkDir) { return Shell.WINDOWS ? @@ -421,7 +440,7 @@ public class DefaultContainerExecutor extends ContainerExecutor { * @param signal signal to send * (for logging). */ - private void killContainer(String pid, Signal signal) throws IOException { + protected void killContainer(String pid, Signal signal) throws IOException { new ShellCommandExecutor(Shell.getSignalKillCommand(signal.getValue(), pid)) .execute(); } http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java index d628b1c..884a16a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java @@ -194,9 +194,12 @@ public class LinuxContainerExecutor extends ContainerExecutor { @Override public void startLocalizer(Path nmPrivateContainerTokensPath, InetSocketAddress nmAddr, String user, String appId, String locId, - List<String> localDirs, List<String> logDirs) + LocalDirsHandlerService dirsHandler) throws IOException, InterruptedException { + List<String> localDirs = dirsHandler.getLocalDirs(); + List<String> logDirs = dirsHandler.getLogDirs(); + verifyUsernamePattern(user); String runAsUser = getRunAsUser(user); List<String> command = new ArrayList<String>();
