コード例 #1
0
        public async Task CreateAndStartContainerWaitForExit(SessionHostsStartInfo startParameters)
        {
            IList <PortMapping> portMappings = GetPortMappings(startParameters, 0);

            if (startParameters.SessionHostType == SessionHostType.Container)
            {
                foreach (PortMapping mapping in portMappings)
                {
                    _logger.LogInformation(
                        $"{mapping.GamePort.Name} ({mapping.GamePort.Protocol}): Local port {mapping.NodePort} mapped to container port {mapping.GamePort.Number} ");
                }
            }

            DownloadAndExtractAllAssets(startParameters);
            DownloadGameCertificates(startParameters);

            ISessionHostRunner sessionHostRunner =
                _sessionHostRunnerFactory.CreateSessionHostRunner(startParameters.SessionHostType, _vmConfiguration, _logger);

            // RetrieveResources does a docker pull
            // If we're running Linux containers on Windows, we might want to pull image from ACR first to save the image on local.
            // In this case, you need to simply change the value to true for forcePullFromAcrOnLinuxContainersOnWindows in MultiplayerSettings.json
            // so if this image is not locally built, docker create will do a docker pull first
            // In another case, we might have built the image locally but tagged with a fake registry name (e.g. myacr.io/mygame:0.1),
            // Then make sure to change the value to false if you want to use the image from local.
            if (Globals.GameServerEnvironment == GameServerEnvironment.Windows || Globals.Settings.ForcePullFromAcrOnLinuxContainersOnWindows)
            {
                await sessionHostRunner.RetrieveResources(startParameters);
            }

            NoOpSessionHostManager sessionHostManager = new NoOpSessionHostManager();
            SessionHostInfo        sessionHostInfo    =
                await sessionHostRunner.CreateAndStart(0, new GameResourceDetails { SessionHostsStartInfo = startParameters }, sessionHostManager);

            if (sessionHostInfo == null)
            {
                return;
            }

            string typeSpecificId = sessionHostInfo.TypeSpecificId;

            _logger.LogInformation("Waiting for heartbeats from the game server.....");

            await sessionHostRunner.WaitOnServerExit(typeSpecificId).ConfigureAwait(false);

            string logFolder = Path.Combine(Globals.VmConfiguration.VmDirectories.GameLogsRootFolderVm, sessionHostInfo.LogFolderId);
            await sessionHostRunner.CollectLogs(typeSpecificId, logFolder, sessionHostManager);

            await sessionHostRunner.TryDelete(typeSpecificId);
        }
コード例 #2
0
        public SessionHostInfo AddNewSessionHost(string sessionHostId, string assignmentId, int instanceNumber, string logFolderId,
                                                 SessionHostType type = SessionHostType.Container)
        {
            var sessionHostInfo = new SessionHostInfo(sessionHostId, assignmentId, instanceNumber, logFolderId, type)
            {
                SessionHostHeartbeatRequest = new SessionHostHeartbeatInfo()
                {
                    AssignmentId               = assignmentId,
                    CurrentGameState           = SessionHostStatus.PendingHeartbeat,
                    LastStateTransitionTimeUtc = DateTime.UtcNow
                }
            };

            SessionHostsMap.TryAdd(sessionHostId, sessionHostInfo);
            return(sessionHostInfo);
        }
コード例 #3
0
ファイル: ProcessRunner.cs プロジェクト: PlayFab/MpsAgent
        public override Task <SessionHostInfo> CreateAndStart(int instanceNumber, GameResourceDetails gameResourceDetails, ISessionHostManager sessionHostManager)
        {
            SessionHostsStartInfo sessionHostStartInfo = gameResourceDetails.SessionHostsStartInfo;
            string sessionHostUniqueId = Guid.NewGuid().ToString("D");
            string logFolderPathOnVm   = Path.Combine(_vmConfiguration.VmDirectories.GameLogsRootFolderVm, sessionHostUniqueId);

            _systemOperations.CreateDirectory(logFolderPathOnVm);

            // Create the dumps folder as a subfolder of the logs folder
            string dumpFolderPathOnVm = Path.Combine(logFolderPathOnVm, VmDirectories.GameDumpsFolderName);

            _systemOperations.CreateDirectory(dumpFolderPathOnVm);

            ISessionHostConfiguration sessionHostConfiguration = new SessionHostProcessConfiguration(_vmConfiguration, _logger, _systemOperations, sessionHostStartInfo);
            string configFolderPathOnVm = _vmConfiguration.GetConfigRootFolderForSessionHost(instanceNumber);

            _systemOperations.CreateDirectory(configFolderPathOnVm);

            ProcessStartInfo processStartInfo = new ProcessStartInfo();

            (string executableFileName, string arguments) = GetExecutableAndArguments(sessionHostStartInfo, instanceNumber);
            processStartInfo.FileName         = executableFileName;
            processStartInfo.Arguments        = arguments;
            processStartInfo.WorkingDirectory = sessionHostStartInfo.GameWorkingDirectory ?? Path.GetDirectoryName(executableFileName);
            processStartInfo.Environment.AddRange(sessionHostConfiguration.GetEnvironmentVariablesForSessionHost(instanceNumber, sessionHostUniqueId, sessionHostManager.VmAgentSettings));

            _logger.LogInformation($"Starting process for session host with instance number {instanceNumber} and process info: FileName - {executableFileName}, Args - {arguments}.");

            SessionHostInfo sessionHost = sessionHostManager.AddNewSessionHost(sessionHostUniqueId, sessionHostStartInfo.AssignmentId, instanceNumber, sessionHostUniqueId, SessionHostType.Process);

            sessionHostConfiguration.Create(instanceNumber, sessionHostUniqueId, GetVmAgentIpAddress(), _vmConfiguration, sessionHostUniqueId);

            try
            {
                string processId = _processWrapper.Start(processStartInfo).ToString();
                sessionHostManager.UpdateSessionHostTypeSpecificId(sessionHostUniqueId, processId);
                _logger.LogInformation($"Started process for session host. Instance Number: {instanceNumber}, UniqueId: {sessionHostUniqueId}, ProcessId: {processId}");
            }
            catch (Exception exception)
            {
                _logger.LogException($"Failed to start process based host with instance number {instanceNumber}", exception);
                sessionHostManager.RemoveSessionHost(sessionHostUniqueId);
                sessionHost = null;
            }

            return(Task.FromResult(sessionHost));
        }
コード例 #4
0
        public async Task CreateAndStartContainerWaitForExit(SessionHostsStartInfo startParameters)
        {
            IList <PortMapping> portMappings = GetPortMappings(startParameters, 0);

            if (startParameters.SessionHostType == SessionHostType.Container)
            {
                foreach (PortMapping mapping in portMappings)
                {
                    _logger.LogInformation(
                        $"{mapping.GamePort.Name} ({mapping.GamePort.Protocol}): Local port {mapping.NodePort} mapped to container port {mapping.GamePort.Number} ");
                }
            }

            DownloadAndExtractAllAssets(startParameters);
            DownloadGameCertificates(startParameters);

            ISessionHostRunner sessionHostRunner =
                _sessionHostRunnerFactory.CreateSessionHostRunner(startParameters.SessionHostType, _vmConfiguration, _logger);

            // RetrieveResources does a docker pull
            // if we're running Linux containers on Windows we do not want that, since we might
            // have built the image locally but tagged with a fake registry name (e.g. myacr.io/mygame:0.1)
            // docker pull will try to connect to myacr.io and fail
            // if this image is not locally built, docker create (executed next) will do a docker pull first
            if (Globals.GameServerEnvironment == GameServerEnvironment.Windows)
            {
                await sessionHostRunner.RetrieveResources(startParameters);
            }

            NoOpSessionHostManager sessionHostManager = new NoOpSessionHostManager();
            SessionHostInfo        sessionHostInfo    =
                await sessionHostRunner.CreateAndStart(0, new GameResourceDetails { SessionHostsStartInfo = startParameters }, sessionHostManager);

            string containerId = sessionHostInfo.TypeSpecificId;

            _logger.LogInformation("Waiting for heartbeats from the game server.....");

            await sessionHostRunner.WaitOnServerExit(containerId).ConfigureAwait(false);

            string logFolder = Path.Combine(Globals.VmConfiguration.VmDirectories.GameLogsRootFolderVm, sessionHostInfo.LogFolderId);
            await sessionHostRunner.CollectLogs(containerId, logFolder, sessionHostManager);

            await sessionHostRunner.TryDelete(containerId);
        }
コード例 #5
0
        /// <summary>
        /// Creates and starts a container, assigning <paramref name="instanceNumber"/> to it.
        /// </summary>
        /// <param name="instanceNumber">
        /// An instance number associated with a container. It is used to map assets folder to the container
        /// and then re-use for container recycling.
        /// </param>
        /// <returns>A <see cref="Task"/>.</returns>
        public async Task <SessionHostInfo> CreateAndStart(int instanceNumber, GameResourceDetails gameResourceDetails, ISessionHostManager sessionHostManager)
        {
            // The current Docker client doesn't yet allow specifying a local name for the image.
            // It is stored with as the remote path name. Thus, the parameter to CreateAndStartContainers
            // is the same as the remote image path.
            SessionHostsStartInfo sessionHostStartInfo = gameResourceDetails.SessionHostsStartInfo;
            ContainerImageDetails imageDetails         = sessionHostStartInfo.ImageDetails;
            string imageName = $"{imageDetails.Registry}/{imageDetails.ImageName}:{imageDetails.ImageTag ?? "latest"}";

            // The game containers need a unique folder to write their logs. Ideally,
            // we would specify the containerId itself as the subfolder. However, we have to
            // specify volume bindings before docker gives us the container id, so using
            // a random guid here instead
            string logFolderId = _systemOperations.NewGuid().ToString("D");
            ISessionHostConfiguration sessionHostConfiguration = new SessionHostContainerConfiguration(_vmConfiguration, _logger, _systemOperations, _dockerClient, sessionHostStartInfo);
            IList <PortMapping>       portMappings             = sessionHostConfiguration.GetPortMappings(instanceNumber);
            List <string>             environmentValues        = sessionHostConfiguration.GetEnvironmentVariablesForSessionHost(instanceNumber, logFolderId)
                                                                 .Select(x => $"{x.Key}={x.Value}").ToList();

            string dockerId = await CreateContainer(
                imageName,
                environmentValues,
                GetVolumeBindings(sessionHostStartInfo, instanceNumber, logFolderId),
                portMappings,
                GetStartGameCmd(sessionHostStartInfo),
                sessionHostStartInfo.HostConfigOverrides,
                GetGameWorkingDir(sessionHostStartInfo));

            SessionHostInfo sessionHost = sessionHostManager.AddNewSessionHost(dockerId, sessionHostStartInfo.AssignmentId, instanceNumber, logFolderId);

            // https://docs.docker.com/docker-for-windows/networking/
            string agentIPaddress = sessionHostManager.LinuxContainersOnWindows ? "host.docker.internal" : GetVmAgentIpAddress();

            sessionHostConfiguration.Create(instanceNumber, dockerId, agentIPaddress, _vmConfiguration, logFolderId);

            // on LinuxContainersForWindows, VMAgent will run in a Windows environment
            // but we want the Linux directory separator char
            if (sessionHostManager.LinuxContainersOnWindows)
            {
                string configFilePath = Path.Combine(_vmConfiguration.GetConfigRootFolderForSessionHost(instanceNumber),
                                                     VmDirectories.GsdkConfigFilename);
                File.WriteAllText(configFilePath, File.ReadAllText(configFilePath).
                                  Replace($"{_vmConfiguration.VmDirectories.GameLogsRootFolderContainer}\\\\",
                                          $"{_vmConfiguration.VmDirectories.GameLogsRootFolderContainer}/"));
            }
            try
            {
                await StartContainer(dockerId);

                _logger.LogInformation($"Started container {dockerId}, with assignmentId {sessionHostStartInfo.AssignmentId}, instance number {instanceNumber}, and logFolderId {logFolderId}");
            }
            catch (Exception exception)
            {
                _logger.LogException($"Failed to start container based host with instance number {instanceNumber}", exception);
                sessionHostManager.RemoveSessionHost(dockerId);
                sessionHost = null;
            }


            return(sessionHost);
        }