public void PublicPortMatchesContainerPort()
        {
            _vmConfiguration = new VmConfiguration(56001, TestVmId, new VmDirectories(_root), true);

            _sessionHostManager.Setup(x => x.LinuxContainersOnWindows).Returns(true);

            VmPathHelper.AdaptFolderPathsForLinuxContainersOnWindows(_vmConfiguration);

            _sessionHostsStartInfo.SessionHostType  = SessionHostType.Container;
            _sessionHostsStartInfo.PortMappingsList = new List <List <PortMapping> >()
            {
                new List <PortMapping>()
                {
                    new PortMapping()
                    {
                        GamePort = new Port()
                        {
                            Name     = "port",
                            Number   = 80,
                            Protocol = "TCP"
                        },
                        PublicPort = 1234,
                        NodePort   = 56001
                    }
                }
            };

            SessionHostContainerConfiguration sessionHostContainerConfiguration =
                new SessionHostContainerConfiguration(_vmConfiguration, _logger, _systemOperations, _dockerClient.Object, _sessionHostsStartInfo, shouldPublicPortMatchGamePort: true);

            IList <PortMapping> result = sessionHostContainerConfiguration.GetPortMappings(0);

            result[0].PublicPort.Should().Be(_sessionHostsStartInfo.PortMappingsList[0][0].PublicPort);
            result[0].GamePort.Number.Should().Be(result[0].PublicPort);
        }
        public void TestEnvVariablesWithSessionLinuxContainerOnWindow()
        {
            _sessionHostManager.Setup(x => x.LinuxContainersOnWindows).Returns(true);

            VmPathHelper.AdaptFolderPathsForLinuxContainersOnWindows(_vmConfiguration);

            _sessionHostsStartInfo.SessionHostType = SessionHostType.Container;

            SessionHostContainerConfiguration sessionHostContainerConfiguration =
                new SessionHostContainerConfiguration(_vmConfiguration, _logger, _systemOperations, _dockerClient.Object, _sessionHostsStartInfo, isRunningLinuxContainersOnWindows: true);

            IDictionary <string, string> envVariables =
                sessionHostContainerConfiguration.GetEnvironmentVariablesForSessionHost(0, TestLogFolderId, _sessionHostManager.Object.VmAgentSettings);

            string containerPath           = _VmDirectoryContainerRoot + "/GameLogs" + "/";
            string sharedContentFolderPath = _VmDirectoryContainerRoot + "/GameSharedContent";
            string gsdkConfigFilePath      = _VmDirectoryContainerRoot + "/Config" + "/gsdkConfig.json";
            string certificateFolderPath   = _VmDirectoryContainerRoot + "/GameCertificates";

            Assert.AreEqual(envVariables[LogsDirectoryEnvVariable], containerPath);
            Assert.AreEqual(envVariables[SharedContentFolderEnvVariable], sharedContentFolderPath);
            Assert.AreEqual(envVariables[ConfigFileEnvVariable], gsdkConfigFilePath);
            Assert.AreEqual(envVariables[CertificateFolderEnvVariable], certificateFolderPath);
        }
        public void TestCreateLegacyGSDKConfigFileWithSessionLinuxContainer()
        {
            _vmConfiguration = new VmConfiguration(56001, TestVmId, new VmDirectories(_root), true);

            _sessionHostManager.Setup(x => x.LinuxContainersOnWindows).Returns(true);

            VmPathHelper.AdaptFolderPathsForLinuxContainersOnWindows(_vmConfiguration);

            _sessionHostsStartInfo.SessionHostType  = SessionHostType.Container;
            _sessionHostsStartInfo.PortMappingsList = new List <List <PortMapping> >()
            {
                new List <PortMapping>()
                {
                    new PortMapping()
                    {
                        GamePort = new Port()
                        {
                            Name     = "port",
                            Number   = 80,
                            Protocol = "TCP"
                        },
                        PublicPort = 1234,
                        NodePort   = 56001
                    }
                }
            };

            List <PortMapping> mockPortMapping = _sessionHostsStartInfo.PortMappingsList[0];

            SessionHostContainerConfiguration sessionHostContainerConfiguration =
                new SessionHostContainerConfiguration(_vmConfiguration, _logger, _systemOperations, _dockerClient.Object, _sessionHostsStartInfo, true);

            sessionHostContainerConfiguration.Create(0, TestdDockerId, TestAgentIPaddress, _vmConfiguration, TestLogFolderId);

            string gsdkConfigFilePath = Path.Combine(_root, "Config", "SH0", "gsdkConfig.json");

            GsdkConfiguration gsdkConfigExpected = new GsdkConfiguration()
            {
                HeartbeatEndpoint = $"{TestAgentIPaddress}:56001",
                SessionHostId     = TestdDockerId,
                VmId                     = TestVmId,
                LogFolder                = "/data/GameLogs/",
                CertificateFolder        = "/data/GameCertificates",
                SharedContentFolder      = "/data/GameSharedContent",
                GamePorts                = mockPortMapping?.ToDictionary(x => x.GamePort.Name, x => x.GamePort.Number.ToString()),
                PublicIpV4Address        = TestPublicIpV4Address,
                GameServerConnectionInfo = new GameServerConnectionInfo
                {
                    PublicIpV4Adress       = TestPublicIpV4Address,
                    GamePortsConfiguration = new List <GamePort>()
                    {
                        new GamePort()
                        {
                            Name = mockPortMapping[0].GamePort.Name,
                            ServerListeningPort  = mockPortMapping[0].GamePort.Number,
                            ClientConnectionPort = mockPortMapping[0].PublicPort
                        }
                    }
                }
            };

            GsdkConfiguration gsdkConfig = JsonConvert.DeserializeObject <GsdkConfiguration>(File.ReadAllText(gsdkConfigFilePath));

            gsdkConfig.Should().BeEquivalentTo(gsdkConfigExpected);
        }
Пример #4
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);
        }