예제 #1
0
        public static bool IsSessionBrokerNode(WindowsIdentity identity, string jobId)
        {
            // BUG 8419 : Cache BN SecurityIdentiy objects to improve latency
            if (!CacheBrokerNodeIdentities(jobId))
            {
                return(false);
            }

            if (!brokerNodeIdentityCache.Contains(identity.User))
            {
                // dump SID list
                string strSIDList = string.Empty;
                foreach (SecurityIdentifier sid in brokerNodeIdentityCache)
                {
                    strSIDList += sid.Value;
                    strSIDList += ",";
                }

                RuntimeTraceHelper.TraceEvent(
                    jobId,
                    TraceEventType.Error,
                    "[HpcServiceHost]: SessionBrokerNodes.IsSessionBrokerNode: {0} is not in cached node list: {1}",
                    identity.User.Value,
                    strSIDList);

                return(false);
            }
            return(true);
        }
예제 #2
0
        /// <summary>
        /// Set the trace level according to the env var
        /// </summary>
        public static void SetTraceSwitchLevel()
        {
            SourceLevels level = Utility.GetTraceSwitchLevel();

            ServiceContext.Logger.Switch.Level = level;

            if (level != SourceLevels.Off)
            {
                RuntimeTraceHelper.IsDiagTraceEnabled = x => true;

                RuntimeTraceHelper.TraceEvent(
                    TraceEventType.Information,
                    SoaHelper.CreateTraceMessage(
                        "Utility",
                        "SetTraceSwitchLevel",
                        "Add the SoaDiagTraceListener."));

                ServiceContext.Logger.Listeners.Add(new SoaDiagTraceListener(Utility.GetJobId()));
            }
            else
            {
                RuntimeTraceHelper.TraceEvent(
                    TraceEventType.Information,
                    SoaHelper.CreateTraceMessage(
                        "Utility",
                        "SetTraceSwitchLevel",
                        "SoaDiagTrace is disabled."));
            }
        }
예제 #3
0
        /// <summary>
        /// Initializes a new instance of the BrokerNodeAuthManager class.
        /// </summary>
        /// <param name="jobId">job id of the soa session</param>
        internal BrokerNodeAuthManager(string jobId)
        {
            this.jobId = jobId;

            if (SoaHelper.IsCurrentUserLocal() || WindowsIdentity.GetCurrent().IsSystem)
            {
                this.enable = false;
                RuntimeTraceHelper.TraceEvent(this.jobId, TraceEventType.Information, "[HpcServiceHost]: BrokerNodeAuthManager is disabled in non-domain joined compute node.");
            }
            else
            {
                this.enable      = true;
                this.allowedUser = WindowsIdentity.GetCurrent();

                // If this environment does not exist, the jobOwnerUserName will remain null.
                // Thus the comparision will always fail so that HpcServiceHost will not authenticate job owner.
                this.jobOwnerUserName = Environment.GetEnvironmentVariable(Constant.JobOwnerNameEnvVar, EnvironmentVariableTarget.Process);

                RuntimeTraceHelper.TraceEvent(
                    this.jobId,
                    TraceEventType.Information,
                    "[HpcServiceHost]: BrokerNodeAuthManager initialized. AllowerUser = {0}, JobOwner = {1}",
                    this.allowedUser.Name,
                    this.jobOwnerUserName);
            }
        }
예제 #4
0
        /// <summary>
        /// Get the full path of the local cache for the service config file,
        /// which is specified by Constant.ServiceConfigFileNameEnvVar.
        /// </summary>
        /// <returns>local cache folder path</returns>
        public static string GetServiceLocalCacheFullPath()
        {
            string path = SoaHelper.GetCcpPackageRoot();

            if (string.IsNullOrEmpty(path))
            {
                RuntimeTraceHelper.TraceEvent(
                    TraceEventType.Error,
                    SoaHelper.CreateTraceMessage(
                        "Utility",
                        "GetServiceLocalCacheFullPath",
                        "The env var CCP_PACKAGE_ROOT has no value"));
            }
            else
            {
                if (Directory.Exists(path))
                {
                    string configFileName = Environment.GetEnvironmentVariable(Constant.ServiceConfigFileNameEnvVar);
                    if (string.IsNullOrEmpty(configFileName))
                    {
                        RuntimeTraceHelper.TraceEvent(
                            TraceEventType.Error,
                            SoaHelper.CreateTraceMessage(
                                "Utility",
                                "GetServiceLocalCacheFullPath",
                                "The env var CCP_SERVICE_CONFIG_FILENAME has no value"));
                    }
                    else
                    {
                        string subFolderName = Path.GetFileNameWithoutExtension(configFileName);
                        string result        = FindLatestSubDirectory(Path.Combine(path, subFolderName));
                        if (!string.IsNullOrEmpty(result) && Directory.Exists(result))
                        {
                            return(result);
                        }
                    }
                }
            }

            // fall back to the home folder, which stores the build-in CcpEchoSvc and HpcSeviceHost.exe
            string home = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            RuntimeTraceHelper.TraceEvent(
                TraceEventType.Information,
                SoaHelper.CreateTraceMessage(
                    "Utility",
                    "GetServiceLocalCacheFullPath",
                    string.Format(CultureInfo.InvariantCulture, "Fall back to the home folder {0}.", home)));

            return(home);
        }
예제 #5
0
        /// <summary>
        /// Shutdowns down service host
        /// </summary>
        /// <param name="state"></param>
        public void Exit()
        {
            try
            {
                lock (this.hostWrapper.SyncObjOnExitingCalled)
                {
                    // No need to call OnExiting again if it is already called when Ctrl-B signal is received.
                    if (!this.hostWrapper.IsOnExitingCalled)
                    {
                        // Invoke user's Exiting event async with a timeout specified by TaskCancelGracePeriod cluster parameter.
                        Action <object> a  = this.InvokeFireExitingEvent;
                        IAsyncResult    ar = a.BeginInvoke(null, null, null);
                        if (ar.AsyncWaitHandle.WaitOne(this._cancelTaskGracePeriod, false))
                        {
                            a.EndInvoke(ar);
                        }

                        this.hostWrapper.IsOnExitingCalled = true;
                    }
                }
            }

            catch (Exception e)
            {
                RuntimeTraceHelper.TraceEvent(
                    this._sessionId,
                    TraceEventType.Warning,
                    "[HpcServiceHost]: Exception calling Exiting - {0}",
                    e);
            }

            finally
            {
                // Keep the exit code the same as before. If the host is cancelled by user or scheduler,
                // it exits with -1. If the host is closed by graceful shrink, it exits with 0.
                if (this.hostWrapper.ReceivedCancelEvent)
                {
                    Console.Out.WriteLine(StringTable.TaskCanceledOrPreempted);
                    Console.Out.Flush();
                    Environment.Exit(-1);
                }
                else
                {
                    Console.Out.WriteLine(StringTable.ServiceShutdownFromBrokerShrink);
                    Console.Out.Flush();
                    Environment.Exit(ErrorCode.Success);
                }
            }
        }
예제 #6
0
        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            Guid messageId;

            request.Headers.MessageId.TryGetGuid(out messageId);

            this.hostWrapper.AllMessageIds.Add(messageId);
            this.hostWrapper.SerivceHostIdleTimer?.Change(Timeout.Infinite, Timeout.Infinite);
            this.hostWrapper.ServiceHangTimer?.Change(this.hostWrapper.ServiceHangTimeout, Timeout.Infinite);

            if (this.propagateActivity)
            {
                Trace.CorrelationManager.ActivityId = messageId;
            }

            // This trace is included in the user trace.
            ServiceContext.Logger.TraceEvent(
                TraceEventType.Verbose,
                0,
                "[HpcServiceHost]: Request is received.");

            RuntimeTraceHelper.TraceEvent(
                TraceEventType.Verbose,
                "[HpcServiceHost]: Request {0} is received.",
                messageId);

            if (this.enableSoaDebugger)
            {
                int machineNameIndex = request.Headers.FindHeader(SoaDebuggerMachineName, string.Empty);
                int portIndex        = request.Headers.FindHeader(SoaDebuggerPort, string.Empty);

                if (0 <= machineNameIndex && machineNameIndex < request.Headers.Count &&
                    0 <= portIndex && portIndex < request.Headers.Count)
                {
                    string ideMachine = request.Headers.GetHeader <string>(machineNameIndex);
                    int    port       = request.Headers.GetHeader <int>(portIndex);

                    string localMachine = Environment.MachineName;
                    int    pid          = Process.GetCurrentProcess().Id;

                    // send back debug info "machinename|pid|jobid" to the VS IDE
                    SendByTcp(ideMachine, port, string.Format(CultureInfo.InvariantCulture, "{0}|{1}|{2}", localMachine, pid, this.sessionId));
                    ServiceContext.Logger.TraceInformation(string.Format(CultureInfo.InvariantCulture, "[HpcServiceHost]: Send debug info to the VS IDE machine {0}:{1}.", ideMachine, port));
                }
            }

            return(messageId);
        }
예제 #7
0
        /// <summary>
        /// Get switch level from job env var.
        /// </summary>
        /// <returns>trace level</returns>
        private static SourceLevels GetTraceSwitchLevel()
        {
            string values = Environment.GetEnvironmentVariable(Constant.TraceSwitchValue);

            RuntimeTraceHelper.TraceEvent(
                TraceEventType.Information,
                "{0}={1}",
                Constant.TraceSwitchValue,
                values);

            SourceLevels level = SourceLevels.Off;

            if (!string.IsNullOrEmpty(values))
            {
                string[] levelStrings = values.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                foreach (string value in levelStrings)
                {
                    try
                    {
                        level |= (SourceLevels)Enum.Parse(typeof(SourceLevels), value, true);
                    }
                    catch (ArgumentException)
                    {
                        RuntimeTraceHelper.TraceEvent(
                            TraceEventType.Error,
                            SoaHelper.CreateTraceMessage(
                                "Utility",
                                "GetTraceSwitchLevel",
                                string.Format(CultureInfo.CurrentCulture, "{0} is not a correct value of SourceLevels.", value)));

                        return(SourceLevels.Off);
                    }
                }

                RuntimeTraceHelper.TraceEvent(
                    TraceEventType.Information,
                    SoaHelper.CreateTraceMessage(
                        "Utility",
                        "GetTraceSwitchLevel",
                        string.Format(CultureInfo.InvariantCulture, "The trace switch level is {0}.", level)));
            }

            return(level);
        }
예제 #8
0
        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            Guid guid = Guid.Empty;

            if (correlationState is Guid)
            {
                guid = (Guid)correlationState;
            }

            // This trace is included in the user trace.
            ServiceContext.Logger.TraceEvent(
                TraceEventType.Verbose,
                0,
                "[HpcServiceHost]: Response is sent back. IsFault = {0}",
                reply.IsFault);

            RuntimeTraceHelper.TraceEvent(
                TraceEventType.Verbose,
                "[HpcServiceHost]: Response {0} is sent back. IsFault = {1}",
                guid,
                reply.IsFault);

            if (this.propagateActivity)
            {
                System.Diagnostics.Trace.CorrelationManager.ActivityId = Guid.Empty;
            }

            if (this.hostWrapper.EnableMessageLevelPreemption)
            {
                // If the message is skipped, reply a fault message to the broker.
                if (this.hostWrapper.SkippedMessageIds.Contains(guid))
                {
                    this.hostWrapper.SkippedMessageIds.Remove(guid);

                    // For Service_Preempted error, reuse SessionFault.reason property to pass "processing message count" to the broker.
                    int          messageCount = this.hostWrapper.ProcessingMessageIds.Count;
                    SessionFault fault        = new SessionFault(SOAFaultCode.Service_Preempted, messageCount.ToString());

                    FaultException faultException = new FaultException <SessionFault>(fault, string.Empty, null, SessionFault.Action);
                    reply = GenerateFaultMessage(guid, reply.Headers.MessageVersion, faultException);
                }
                else if (this.hostWrapper.ProcessingMessageIds.Contains(guid))
                {
                    this.hostWrapper.ProcessingMessageIds.Remove(guid);

                    // The service host receives the cancel event when the request is being processed, so add a header to notice the broker.
                    if (this.hostWrapper.ReceivedCancelEvent)
                    {
                        // Use the header to pass "processing message count" to the broker.
                        int messageCount = this.hostWrapper.ProcessingMessageIds.Count;
                        reply.Headers.Add(MessageHeader.CreateHeader(Constant.MessageHeaderPreemption, Constant.HpcHeaderNS, messageCount));
                    }
                }
                else
                {
                    // If the message is not in above two lists, the message doesn't come into the invoker. No need to change its response.
                }
            }

            if (this.hostWrapper.AllMessageIds.Contains(guid))
            {
                this.hostWrapper.AllMessageIds.Remove(guid);
                lock (this.hostWrapper.AllMessageIds.SyncRoot)
                {
                    if (this.hostWrapper.AllMessageIds.Count == 0)
                    {
                        this.hostWrapper.SerivceHostIdleTimer?.Change(this.hostWrapper.ServiceHostIdleTimeout, Timeout.Infinite);
                        this.hostWrapper.ServiceHangTimer?.Change(Timeout.Infinite, Timeout.Infinite);
                    }
                    else
                    {
                        this.hostWrapper.ServiceHangTimer?.Change(this.hostWrapper.ServiceHangTimeout, Timeout.Infinite);
                    }
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Returned broker node identity cache
        /// </summary>
        /// <returns></returns>
        private static bool CacheBrokerNodeIdentities(string jobId)
        {
            bool ret = true;

            if (brokerNodeIdentityCache == null)
            {
                lock (brokerNodeIdentityCacheLock)
                {
                    if (brokerNodeIdentityCache == null)
                    {
                        try
                        {
                            IDictionary envVars = Environment.GetEnvironmentVariables();

                            // Extract the number of BNs
                            string nodeCountStr = (string)envVars[BrokerCountEnvVarName];

                            int nodeCount = 0;
                            if (string.IsNullOrEmpty(nodeCountStr) || !int.TryParse(nodeCountStr, out nodeCount))
                            {
                                RuntimeTraceHelper.TraceEvent(
                                    jobId,
                                    TraceEventType.Error,
                                    "[HpcServiceHost]: SessionBrokerNodes.CacheBrokerNodeIdentities: return false because nodeCountStr={0}",
                                    nodeCountStr);

                                return(false);
                            }

                            if (nodeCount <= 0)
                            {
                                RuntimeTraceHelper.TraceEvent(
                                    jobId,
                                    TraceEventType.Error,
                                    "[HpcServiceHost]: SessionBrokerNodes.CacheBrokerNodeIdentities: return false because nodeCount={0}",
                                    nodeCount);

                                return(false);
                            }

                            // Enum each BN and create a SecurityIdentifier for it
                            brokerNodeIdentityCache = new List <SecurityIdentifier>();

                            for (int i = 0; i < nodeCount; i++)
                            {
                                string nodeSSDL = (string)envVars[string.Format(BrokerNameEnvVarNameTemplate, i + 1)];

                                // Create BN identity using SecurityIdentifier. This ensures correct comparison (including same domain - Bug 6787).
                                SecurityIdentifier brokerNodeIdentity = new SecurityIdentifier(nodeSSDL);
                                brokerNodeIdentityCache.Add(brokerNodeIdentity);

                                RuntimeTraceHelper.TraceEvent(
                                    jobId,
                                    TraceEventType.Verbose,
                                    "[HpcServiceHost]: SessionBrokerNodes.CacheBrokerNodeIdentities: cached node: node SSDL={0}, SID={1}",
                                    nodeSSDL,
                                    brokerNodeIdentity.Value);
                            }
                        }

                        catch (Exception e)
                        {
                            RuntimeTraceHelper.TraceEvent(
                                jobId,
                                TraceEventType.Error,
                                "[HpcServiceHost]: Fail to cache broker node identities for broker node authentication. - {0}",
                                e);

                            ret = false;
                        }
                    }
                }
            }

            return(ret);
        }
예제 #10
0
        /// <summary>
        /// Get service assembly file
        /// </summary>
        /// <param name="serviceConfigName">indicating service configuration file</param>
        /// <param name="onAzure">on azure or in on-premise cluster</param>
        /// <param name="registration">output service registration instance</param>
        /// <param name="serviceAssemblyFullPath">full path of the soa service assembly</param>
        /// <returns>returns return code</returns>
        public static int GetServiceRegistration(string serviceConfigName, bool onAzure, out ServiceRegistration registration, out string serviceAssemblyFullPath)
        {
            // Open the service registration configuration section
            ExeConfigurationFileMap map = new ExeConfigurationFileMap();

            map.ExeConfigFilename = serviceConfigName;

            Configuration config = null;

            RetryManager.RetryOnceAsync(
                () => config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None),
                TimeSpan.FromSeconds(1),
                ex => ex is ConfigurationErrorsException)
            .GetAwaiter()
            .GetResult();
            Debug.Assert(config != null, "Configuration is not opened properly.");

            registration = ServiceRegistration.GetSectionGroup(config);

            serviceAssemblyFullPath = registration.Service.AssemblyPath;
            if (!string.IsNullOrEmpty(serviceAssemblyFullPath))
            {
                serviceAssemblyFullPath = Environment.ExpandEnvironmentVariables(serviceAssemblyFullPath);
            }

            if (onAzure)
            {
                bool exists = false;

                try
                {
                    exists = File.Exists(serviceAssemblyFullPath);
                }
                catch (Exception e)
                {
                    RuntimeTraceHelper.TraceEvent(
                        TraceEventType.Error,
                        SoaHelper.CreateTraceMessage(
                            "Utility",
                            "GetServiceLocalCacheFullPath",
                            string.Format("Exception happens when check the file existence. {0}", e)));
                }

                if (!exists)
                {
                    // If we find the service registration file under the specified path, use it.
                    // Otherwise, fall back to the package root folder. The service assembly is under the same folder as the registration file.
                    serviceAssemblyFullPath = Path.Combine(Path.GetDirectoryName(serviceConfigName), Path.GetFileName(serviceAssemblyFullPath));
                }
            }

            if (string.IsNullOrEmpty(serviceAssemblyFullPath))
            {
                string message = string.Format(CultureInfo.CurrentCulture, StringTable.AssemblyFileNotRegistered, serviceConfigName);
                Console.Error.WriteLine(message);
                RuntimeTraceHelper.TraceEvent(TraceEventType.Error, message);

                return(ErrorCode.ServiceHost_AssemblyFileNameNullOrEmpty);
            }

            if (!File.Exists(serviceAssemblyFullPath))
            {
                // If the obtained service assembly path is not valid or not existing
                string message = string.Format(CultureInfo.CurrentCulture, StringTable.AssemblyFileCantFind, serviceAssemblyFullPath);
                Console.Error.WriteLine(message);
                RuntimeTraceHelper.TraceEvent(TraceEventType.Error, message);

                return(ErrorCode.ServiceHost_AssemblyFileNotFound);
            }

            return(ErrorCode.Success);
        }
예제 #11
0
        /// <summary>
        /// Called to auth each request
        /// </summary>
        /// <param name="operationContext">Operation's context</param>
        /// <returns>pass validation or not</returns>
        protected override bool CheckAccessCore(OperationContext operationContext)
        {
            if (this.enable == false)
            {
                RuntimeTraceHelper.TraceEvent(
                    this.jobId,
                    TraceEventType.Verbose,
                    "[HpcServiceHost]: BrokerNodeAuthManager is disabled.");
                return(true);
            }

            WindowsIdentity callerIdentity = null;
            bool            result         = SoaHelper.CheckWindowsIdentity(operationContext, out callerIdentity);

            if (result && callerIdentity == null)
            {
                // this code path is for Azure.
                return(true);
            }

            if (callerIdentity == null || !result || operationContext.ServiceSecurityContext.IsAnonymous)
            {
                RuntimeTraceHelper.TraceEvent(this.jobId, TraceEventType.Warning, "[HpcServiceHost]: Access denied by BrokerNodeAuthManager. WindowsIdeneity is not recognized.");
                return(false);
            }

            RuntimeTraceHelper.TraceEvent(this.jobId, TraceEventType.Verbose, "[HpcServiceHost]: received request from {0}", callerIdentity.Name);

            // if this is calling from local
            if (callerIdentity.IsSystem)
            {
                return(true);
            }

            // Bug 11378: Authenticate job owner also for inprocess broker
            if (callerIdentity.Name.Equals(this.jobOwnerUserName, StringComparison.InvariantCultureIgnoreCase))
            {
                RuntimeTraceHelper.TraceEvent(
                    this.jobId,
                    TraceEventType.Verbose,
                    "[HpcServiceHost]: Authenticate job owner {0} for inprocess broker.",
                    this.jobOwnerUserName);

                return(true);
            }

            // is this call from a BN
            if (SessionBrokerNodes.IsSessionBrokerNode(callerIdentity, this.jobId))
            {
                return(true);
            }

            RuntimeTraceHelper.TraceEvent(
                this.jobId,
                TraceEventType.Warning,
                "[HpcServiceHost]: {0}/SID={1} is not a broker node",
                callerIdentity.Name,
                callerIdentity.User.Value);

            // Last see if the caller is the 'run as' user for the process. This is mainly needed for diag tests
            if (callerIdentity.User == this.allowedUser.User)
            {
                return(true);
            }
            else
            {
                RuntimeTraceHelper.TraceEvent(
                    this.jobId,
                    TraceEventType.Warning,
                    "[HpcServiceHost]: Access denied by BrokerNodeAuthManager. {0} is not allowed.",
                    callerIdentity.User);
                return(false);
            }
        }