public async Task DeleteResources(SessionHostsStartInfo sessionHostsStartInfo) { ContainerImageDetails imageDetails = sessionHostsStartInfo.ImageDetails; string imageName = $"{imageDetails.Registry}/{imageDetails.ImageName}:{imageDetails.ImageTag ?? "latest"}"; _logger.LogInformation($"Starting deletion of container image {imageName}"); try { await _dockerClient.Images.DeleteImageAsync(imageName, new ImageDeleteParameters() { Force = true }); _logger.LogInformation($"Deleted container image {imageName}"); } catch (DockerImageNotFoundException) { _logger.LogInformation($"Image {imageName} not found."); } }
/// <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); }