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); }
/// <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); }