示例#1
0
        public void CanProxiseByAppid()
        {
            var aconfig1 = new HostConfig();
            aconfig1.AddQorpentBinding(98);
            var aconfig2 = new HostConfig();
            aconfig2.AddQorpentBinding(99);
            aconfig2.Proxize["/call1"] = "appid=98";
            var h1 = new HostServer(aconfig1);
            var h2 = new HostServer(aconfig2);
            h1.On("/call1", "hello!");
            var result = "";
            try
            {
                h1.Start();
                h2.Start(); 
                Thread.Sleep(100);
                result = new HttpClient().GetString("http://127.0.0.1:14990/call1");
            }
            finally
            {
                h1.Stop();
                h2.Stop();

            }
            Assert.AreEqual("hello!", result);
        }
 public override void InitHostConifg(HostConfig config)
 {
     if (config.HandlerFactoryPath == null)
     {
         InferHttpHandlerPath(config);
     }
 }
        private static void InferHttpHandlerPath(HostConfig config)
        {
            try
            {
                var webConfig = GetAppConfig();
                if (webConfig == null) return;

                SetPathsFromConfiguration(config, webConfig, null);

                if (config.MetadataRedirectPath == null)
                {
                    foreach (ConfigurationLocation location in webConfig.Locations)
                    {
                        SetPathsFromConfiguration(config, location.OpenConfiguration(), (location.Path ?? "").ToLower());

                        if (config.MetadataRedirectPath != null) { break; }
                    }
                }

                if (HostContext.IsAspNetHost && config.MetadataRedirectPath == null)
                {
                    throw new ConfigurationErrorsException(
                        "Unable to infer ServiceStack's <httpHandler.Path/> from the Web.Config\n"
                        + "Check with https://github.com/ServiceStack/ServiceStack/wiki/Create-your-first-webservice to ensure you have configured ServiceStack properly.\n"
                        + "Otherwise you can explicitly set your httpHandler.Path by setting: EndpointHostConfig.ServiceStackPath");
                }
            }
            catch (Exception) { }
        }
示例#4
0
        protected override void When()
        {
            FakeMessageChannel.Reset();
            LogManager.Configure(new TraceLoggerFactory(), LogLevel.All);

            var objectFactory = ObjectFactoryResolver.GetObjectFactory();
            objectFactory.Register<ISubscriptionStorage, InMemorySubscriptionStorage>(LifeCycle.Unique);

            var hostConfig = new HostConfig();
            var host = new Host(hostConfig);
            host.Start();
        }
示例#5
0
		public void CanCheckoutConfigUsingMachineNameToResolve() {
			const string code = @"
class local
     connection a y

class remote
     machine t use=^local
     connection b z
";
			var ctx = BSharpCompiler.Compile(code);
			var local = ctx["local"].Compiled;
			var remote = ctx["remote"].Compiled;
			var config = new HostConfig(remote, ctx, "t");
			Assert.AreSame(local, config.Definition);
		}
示例#6
0
        public void CanProxisePost()
        {
            var aconfig1 = new HostConfig();
            aconfig1.AddQorpentBinding(98);
            var aconfig2 = new HostConfig();
            aconfig2.AddQorpentBinding(99);
            aconfig2.Proxize["/call1"] = "appid=98";
            var h1 = new HostServer(aconfig1);
            var h2 = new HostServer(aconfig2);
            h1.OnContext("/call1", _ => {
                if (_.Method == "POST") {
                    _.Finish(new StreamReader(_.Request.Stream).ReadToEnd());
                }
                else {
                    _.Finish("hello!");    
                }
                
            });
            var result = "";
            var resultDirect = "";

            try
            {
                h1.Start();
                h2.Start();
                Thread.Sleep(1000);
                resultDirect = new HttpClient().GetString("http://127.0.0.1:14980/call1", "hello2");
                result = new HttpClient().GetString("http://127.0.0.1:14990/call1", "hello2");
            }
            finally
            {
                h1.Stop();
                h2.Stop();

            }
            Console.WriteLine(result);

            Assert.AreEqual("hello2", resultDirect);
            Assert.AreEqual("hello2", result);
        }
示例#7
0
	    private static void LogHostInfo(ServerParameters arg, HostConfig config) {
            Console.WriteLine("BinRoot: "+config.DllFolder);
	        foreach (var assembly in config.AutoconfigureAssemblies) {
                arg.Log.Trace("Lib: " + assembly);
	        }
	        foreach (var hostBinding in config.Bindings) {
                arg.Log.Info("Binding: " + hostBinding);
	        }
	        arg.Log.Trace("RootFolder: " + config.RootFolder);
	        foreach (var contentFolder in config.ContentFolders) {
	            arg.Log.Trace("ContentFolder: " + contentFolder);
	        }
	        foreach (var map in config.StaticContentMap) {
	            arg.Log.Trace("Map: "+map.Key+" : "+map.Value);
	        }
            foreach (var map in config.Proxize)
            {
                arg.Log.Trace("Proxize: " + map.Key + " : " + map.Value);
            }
	        foreach (var e in config.StaticContentCacheMap) {
	            arg.Log.Trace(e.Value.ToString());
	        }
	    }
示例#8
0
	    private static void EnsureRequiredApplications(ServerParameters serverParameters, HostConfig config) {
	        var requires = config.Definition.Elements("require");
	        foreach (var require in requires) {
                if(!string.IsNullOrWhiteSpace(require.Attr("server")))continue; //external service
	            var name = require.IdCodeOrValue()+require.Attr("suffix");
	            var shadow = EnvironmentInfo.GetShadowDirectory(name);
	            var processes = Process.GetProcessesByName("qh");
                Console.WriteLine(string.Join("; ",processes.Select(_=>_.ProcessName)));
	            var required =
	                processes.FirstOrDefault(_ => _.MainModule.FileName.NormalizePath().StartsWith(shadow.NormalizePath()));
	            if (null != required) {
	                config.Log.Info("Required '" + name + "' found, PID: " + required.Id);
	            }
	            else {
	                var args = name;
	                if (serverParameters.Get("hidden", false)) {
	                    args += " --hidden";
	                }
	                required = Process.Start(EnvironmentInfo.ResolvePath("@repos@/.build/bin/all/qh.exe"), args);
                    config.Log.Info("Required '" + name + "' started, PID: " + required.Id);
	            }
	        }
	    }
示例#9
0
 public Repository(HostConfig config)
 {
     _dataFolder = config.Data;
 }
示例#10
0
        private static void SetPaths(HostConfig config, string handlerPath, string locationPath)
        {
            if (handlerPath == null) return;

            if (locationPath == null)
            {
                handlerPath = handlerPath.Replace("*", String.Empty);
            }

            config.HandlerFactoryPath = locationPath ??
                                        (String.IsNullOrEmpty(handlerPath) ? null : handlerPath);

            config.MetadataRedirectPath = "metadata";
        }
示例#11
0
        private static void SetPathsFromConfiguration(HostConfig config, System.Configuration.Configuration webConfig, string locationPath)
        {
            if (webConfig == null)
                return;

            //standard config
            var handlersSection = webConfig.GetSection("system.web/httpHandlers") as HttpHandlersSection;
            if (handlersSection != null)
            {
                for (var i = 0; i < handlersSection.Handlers.Count; i++)
                {
                    var httpHandler = handlersSection.Handlers[i];
                    if (!httpHandler.Type.StartsWith("ServiceStack"))
                        continue;

                    SetPaths(config, httpHandler.Path, locationPath);
                    break;
                }
            }

            //IIS7+ integrated mode system.webServer/handlers
            var pathsNotSet = config.MetadataRedirectPath == null;
            if (pathsNotSet)
            {
                var webServerSection = webConfig.GetSection("system.webServer");
                var rawXml = webServerSection?.SectionInformation.GetRawXml();
                if (!String.IsNullOrEmpty(rawXml))
                {
                    SetPaths(config, ExtractHandlerPathFromWebServerConfigurationXml(rawXml), locationPath);
                }

                //In some MVC Hosts auto-inferencing doesn't work, in these cases assume the most likely default of "/api" path
                pathsNotSet = config.MetadataRedirectPath == null;
                if (pathsNotSet)
                {
                    var isMvcHost = Type.GetType("System.Web.Mvc.Controller") != null;
                    if (isMvcHost)
                    {
                        SetPaths(config, "api", null);
                    }
                }
            }
        }
        private async Task CreateContainerAsync()
        {
            var hostConfig = new HostConfig
            {
                PublishAllPorts = true
            };

            if (_settings.ExternalPort > 0)
            {
                hostConfig.PublishAllPorts = false;
                hostConfig.PortBindings    = new Dictionary <string, IList <PortBinding> > {
                    {
                        _settings.InternalPort + "/tcp", new List <PortBinding> {
                            new PortBinding {
                                HostPort = _settings.ExternalPort.ToString()
                            }
                        }
                    }
                };
            }

            var startParams = new CreateContainerParameters
            {
                Name         = _settings.UniqueContainerName,
                Image        = _settings.ImageFullname,
                Volumes      = _settings.Volumes.ToDictionary(k => k, v => new EmptyStruct()),
                AttachStdout = true,
                AttachStderr = true,
                AttachStdin  = false,
                Tty          = false,
                HostConfig   = hostConfig,
                Env          = _settings.EnvironmentVariables,
                Cmd          = _settings.Cmd
            };

            try
            {
                await retryPolicy
                .ExecuteAsync(async() =>
                {
                    CreateContainerResponse response = await _client
                                                       .Containers
                                                       .CreateContainerAsync(startParams);

                    if (string.IsNullOrEmpty(response.ID))
                    {
                        throw new ContainerException(
                            "Could not create the container");
                    }
                    Instance.Id   = response.ID;
                    Instance.Name = startParams.Name;
                });

                foreach (CopyContext copyContext in _settings.FilesToCopy)
                {
                    await CopyToContainerAsync(copyContext, true);
                }
            }
            catch (Exception ex)
            {
                throw new ContainerException(
                          $"Error in CreateContainer: {_settings.UniqueContainerName}", ex);
            }
        }
示例#13
0
 public AADTokenHelper(ClientConfig clientConfig, HostConfig hostConfig)
 {
     this.clientConfig = clientConfig;
     this.hostConfig   = hostConfig;
 }
示例#14
0
 public SshConnector(HostConfig hostConfig)
 {
     this.HostConfig = hostConfig;
 }
示例#15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ContainerInspectResponse" /> class.
 /// </summary>
 /// <param name="id">The ID of the container.</param>
 /// <param name="created">The time the container was created.</param>
 /// <param name="path">The path to the command being run.</param>
 /// <param name="args">The arguments to the command being run.</param>
 /// <param name="state">state.</param>
 /// <param name="image">The container&#39;s image.</param>
 /// <param name="resolvConfPath">resolvConfPath.</param>
 /// <param name="hostnamePath">hostnamePath.</param>
 /// <param name="hostsPath">hostsPath.</param>
 /// <param name="logPath">logPath.</param>
 /// <param name="node">TODO.</param>
 /// <param name="name">name.</param>
 /// <param name="restartCount">restartCount.</param>
 /// <param name="driver">driver.</param>
 /// <param name="mountLabel">mountLabel.</param>
 /// <param name="processLabel">processLabel.</param>
 /// <param name="appArmorProfile">appArmorProfile.</param>
 /// <param name="execIDs">IDs of exec instances that are running in the container..</param>
 /// <param name="hostConfig">hostConfig.</param>
 /// <param name="graphDriver">graphDriver.</param>
 /// <param name="sizeRw">The size of files that have been created or changed by this container..</param>
 /// <param name="sizeRootFs">The total size of all the files in this container..</param>
 /// <param name="mounts">mounts.</param>
 /// <param name="config">config.</param>
 /// <param name="networkSettings">networkSettings.</param>
 public ContainerInspectResponse(string id = default(string), string created = default(string), string path = default(string), List <string> args = default(List <string>), ContainerInspectResponseState state = default(ContainerInspectResponseState), string image = default(string), string resolvConfPath = default(string), string hostnamePath = default(string), string hostsPath = default(string), string logPath = default(string), Object node = default(Object), string name = default(string), int?restartCount = default(int?), string driver = default(string), string mountLabel = default(string), string processLabel = default(string), string appArmorProfile = default(string), List <string> execIDs = default(List <string>), HostConfig hostConfig = default(HostConfig), GraphDriverData graphDriver = default(GraphDriverData), long?sizeRw = default(long?), long?sizeRootFs = default(long?), List <MountPoint> mounts = default(List <MountPoint>), ContainerConfig config = default(ContainerConfig), NetworkSettings networkSettings = default(NetworkSettings))
 {
     this.Id              = id;
     this.Created         = created;
     this.Path            = path;
     this.Args            = args;
     this.State           = state;
     this.Image           = image;
     this.ResolvConfPath  = resolvConfPath;
     this.HostnamePath    = hostnamePath;
     this.HostsPath       = hostsPath;
     this.LogPath         = logPath;
     this.Node            = node;
     this.Name            = name;
     this.RestartCount    = restartCount;
     this.Driver          = driver;
     this.MountLabel      = mountLabel;
     this.ProcessLabel    = processLabel;
     this.AppArmorProfile = appArmorProfile;
     this.ExecIDs         = execIDs;
     this.HostConfig      = hostConfig;
     this.GraphDriver     = graphDriver;
     this.SizeRw          = sizeRw;
     this.SizeRootFs      = sizeRootFs;
     this.Mounts          = mounts;
     this.Config          = config;
     this.NetworkSettings = networkSettings;
 }
示例#16
0
        public void CanSetupValidProxyModeFromBSharp() {
            const string code = @"
class myapp
       proxize /others appid=15
       proxize /others2 appid=16 secure=true
       proxize /others3 url='http://yandex.ru'
";
            var xml = BSharpCompiler.Compile(code)["myapp"].Compiled;
            var config = new HostConfig(xml);
            Assert.AreEqual("appid=15;",config.Proxize["/others"]);
            Assert.AreEqual("appid=16;secure=true;",config.Proxize["/others2"]);
            Assert.AreEqual("http://yandex.ru", config.Proxize["/others3"]);
        }
        private async Task StartRedisContainer()
        {
            try
            {
                var dockerConnection = System.Environment.OSVersion.Platform.ToString().Contains("Win") ?
                                       "npipe://./pipe/docker_engine" :
                                       "unix:///var/run/docker.sock";
                System.Console.WriteLine("Starting container");
                using (var conf = new DockerClientConfiguration(new Uri(dockerConnection))) // localhost
                    using (var client = conf.CreateClient())
                    {
                        System.Console.WriteLine("On Premise execution detected");
                        System.Console.WriteLine("Starting container...");
                        var containers = await client.Containers.ListContainersAsync(new ContainersListParameters()
                        {
                            All = true
                        });

                        System.Console.WriteLine("listing container...");
                        var container = containers.FirstOrDefault(c => c.Names.Contains("/" + ContainerName));

                        // Download image
                        await client.Images.CreateImageAsync(new ImagesCreateParameters()
                        {
                            FromImage = ImageName, Tag = ImageTag
                        }, new AuthConfig(), new Progress <JSONMessage>());

                        // Create the container
                        var config = new Config()
                        {
                            Hostname = "localhost"
                        };
                        this.redisPort = Interlocked.Increment(ref uniqueRedisPort);
                        System.Console.WriteLine(this.redisPort);

                        // Configure the ports to expose
                        var hostConfig = new HostConfig()
                        {
                            PortBindings = new Dictionary <string, IList <PortBinding> >
                            {
                                {
                                    $"6379/tcp", new List <PortBinding> {
                                        new PortBinding {
                                            HostIP = "127.0.0.1", HostPort = this.redisPort.ToString()
                                        }
                                    }
                                }
                            }
                        };

                        System.Console.WriteLine("Creating container...");
                        // Create the container
                        var response = await client.Containers.CreateContainerAsync(new CreateContainerParameters(config)
                        {
                            Image      = ImageName + ":" + ImageTag,
                            Name       = ContainerName + this.redisPort,
                            Tty        = false,
                            HostConfig = hostConfig
                        });

                        this.containerId = response.ID;

                        System.Console.WriteLine("Starting container...");

                        var started = await client.Containers.StartContainerAsync(this.containerId, new ContainerStartParameters());

                        if (!started)
                        {
                            Assert.False(true, "Cannot start the docker container");
                        }

                        System.Console.WriteLine("Finish booting sequence container...");
                    }
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex.ToString());
            }
        }
 public CreateDeploymentHandler(Repository repository, HostConfig config)
 {
     _repository = repository;
     _config     = config;
 }
示例#19
0
        public void ValidatePodPropertyTranslation()
        {
            var identity = new ModuleIdentity("hostname", "gatewayhost", "deviceid", "Module1", Mock.Of <ICredentials>());
            var labels   = new Dictionary <string, string>
            {
                // Add a label
                { "demo", "test" }
            };
            var hostConfig = new HostConfig
            {
                // Make container privileged
                Privileged = true,
                // Add a readonly mount
                Binds = new List <string> {
                    "/home/blah:/home/blah2:ro"
                }
            };
            var config       = new KubernetesConfig("image", CreatePodParameters.Create(labels: labels, hostConfig: hostConfig), Option.None <AuthConfig>());
            var docker       = new DockerModule("module1", "v1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, Constants.DefaultStartupOrder, DefaultConfigurationInfo, EnvVarsDict);
            var module       = new KubernetesModule(docker, config, EdgeletModuleOwner);
            var moduleLabels = new Dictionary <string, string>();
            var mapper       = CreateMapper();

            var deployment = mapper.CreateDeployment(identity, module, moduleLabels);
            var pod        = deployment.Spec.Template;

            Assert.NotNull(pod);
            // Validate annotation
            Assert.True(pod.Metadata.Annotations.ContainsKey("demo"));
            // Two containers should exist - proxy and the module
            Assert.Equal(2, pod.Spec.Containers.Count);

            // There should only be one module container
            var moduleContainer = pod.Spec.Containers.Single(p => p.Name != "proxy");

            // We made this container privileged
            Assert.True(moduleContainer.SecurityContext.Privileged);
            // Validate that there are 1 mounts for module container
            Assert.Equal(1, moduleContainer.VolumeMounts.Count);
            // Validate the custom mount that we added
            Assert.Contains(moduleContainer.VolumeMounts, vm => vm.Name.Equals("homeblah"));
            var mount = moduleContainer.VolumeMounts.Single(vm => vm.Name.Equals("homeblah"));

            // Lets make sure that it is read only
            Assert.True(mount.ReadOnlyProperty);

            // Validate proxy container
            var proxyContainer = pod.Spec.Containers.Single(p => p.Name == "proxy");

            // Validate that there are 2 mounts for proxy container: config and trust-bundle
            Assert.Equal(2, proxyContainer.VolumeMounts.Count);
            Assert.Contains(proxyContainer.VolumeMounts, vm => vm.Name.Equals("configVolumeName"));
            Assert.Contains(proxyContainer.VolumeMounts, vm => vm.Name.Equals("trustBundleVolumeName"));

            // Validate pod volumes
            Assert.Equal(3, pod.Spec.Volumes.Count);
            Assert.Contains(pod.Spec.Volumes, v => v.Name.Equals("homeblah"));
            Assert.Contains(pod.Spec.Volumes, v => v.Name.Equals("configVolumeName"));
            Assert.Contains(pod.Spec.Volumes, v => v.Name.Equals("trustBundleVolumeName"));

            // Validate no image pull secrets for public images
            Assert.Null(pod.Spec.ImagePullSecrets);

            // Validate null pod security context by default
            Assert.Null(pod.Spec.SecurityContext);
        }
示例#20
0
        public void CanSetupRequireWithProxying()
        {
            const string code = @"
class app1
     appid 76
     service /myserv1

class app2
     appid 78
     require app1 proxize
";
            var ctx = BSharpCompiler.Compile(code);
            var app = ctx["app2"].Compiled;
            var config = new HostConfig(app,ctx);
            Assert.AreEqual("appid=76;", config.Proxize["/myserv1"]);
        }
示例#21
0
 public RenderContext(HostConfig hostConfig, Dictionary <Type, Func <TypedElement, RenderContext, HtmlTag> > elementRenderers)
 {
     // clone it
     this.Config           = JsonConvert.DeserializeObject <HostConfig>(JsonConvert.SerializeObject(hostConfig));
     this.ElementRenderers = elementRenderers;
 }
示例#22
0
        public async Task <string> RunAsync(TestcontainersConfiguration config, CancellationToken ct = default)
        {
            var image = config.Container.Image;

            var imageExistsTask = DockerApiClientImage.Instance.ExistsWithNameAsync(image);

            var pullImageTask = Task.CompletedTask;

            if (!await imageExistsTask)
            {
                pullImageTask = Docker.Images.CreateImageAsync(new ImagesCreateParameters {
                    FromImage = image
                }, null, DebugProgress.Instance, ct);
            }

            var name = config.Container.Name;

            var workingDir = config.Container.WorkingDirectory;

            var converter = new TestcontainersConfigurationConverter(config);

            var entrypoint = converter.Entrypoint;

            var cmd = converter.Command;

            var env = converter.Environments;

            var labels = converter.Labels;

            var exposedPorts = converter.ExposedPorts;

            var portBindings = converter.PortBindings;

            var mounts = converter.Mounts;

            var hostConfig = new HostConfig
            {
                PortBindings = portBindings,
                Mounts       = mounts,
            };

            var createParameters = new CreateContainerParameters
            {
                Image        = image,
                Name         = name,
                WorkingDir   = workingDir,
                Entrypoint   = entrypoint,
                Env          = env,
                Labels       = labels,
                Cmd          = cmd,
                ExposedPorts = exposedPorts,
                HostConfig   = hostConfig,
            };

            await pullImageTask;

            var id = (await Docker.Containers.CreateContainerAsync(createParameters, ct)).ID;

            TestcontainersRegistryService.Register(id, config.CleanUp);

            return(id);
        }
示例#23
0
        private static void EnsureRequiredApplications(ServerParameters serverParameters, HostConfig config)
        {
            var requires = config.Definition.Elements("require");

            foreach (var require in requires)
            {
                if (!string.IsNullOrWhiteSpace(require.Attr("server")))
                {
                    continue;                                                   //external service
                }
                var name      = require.IdCodeOrValue() + require.Attr("suffix");
                var shadow    = EnvironmentInfo.GetShadowDirectory(name);
                var processes = Process.GetProcessesByName("qh");
                Console.WriteLine(string.Join("; ", processes.Select(_ => _.ProcessName)));
                var required =
                    processes.FirstOrDefault(_ => _.MainModule.FileName.NormalizePath().StartsWith(shadow.NormalizePath()));
                if (null != required)
                {
                    config.Log.Info("Required '" + name + "' found, PID: " + required.Id);
                }
                else
                {
                    var args = name;
                    if (serverParameters.Get("hidden", false))
                    {
                        args += " --hidden";
                    }
                    required = Process.Start(EnvironmentInfo.ResolvePath("@repos@/.build/bin/all/qh.exe"), args);
                    config.Log.Info("Required '" + name + "' started, PID: " + required.Id);
                }
            }
        }
示例#24
0
 public Host Build()
 {
     var hostConfig = new HostConfig();
     return new Host(hostConfig);
 }
示例#25
0
        private async Task <string> CreateContainer(
            string imageName,
            IList <string> environmentVariables,
            IList <string> volumeBindings,
            IList <PortMapping> portMappings,
            IList <string> startCmd,
            HostConfig hostConfigOverrides,
            string workingDirectory)
        {
            HostConfig hostConfig = hostConfigOverrides ?? new HostConfig();

            hostConfig.NetworkMode  = SessionHostContainerConfiguration.DockerNetworkName;
            hostConfig.Binds        = volumeBindings;
            hostConfig.PortBindings = portMappings?.ToDictionary(p => $"{p.GamePort.Number}/{p.GamePort.Protocol}",
                                                                 p => (IList <PortBinding>)(new List <PortBinding>()
            {
                new PortBinding()
                {
                    HostPort = $"{p.NodePort}/{p.GamePort.Protocol}"
                }
            }));
            hostConfig.CapAdd ??= new List <string>();

            if (_systemOperations.IsOSPlatform(OSPlatform.Linux))
            {
                hostConfig.CapAdd.Add("SYS_PTRACE");
            }


            if (hostConfig.LogConfig == null)
            {
                hostConfig.LogConfig        = new LogConfig();
                hostConfig.LogConfig.Type   = "json-file";
                hostConfig.LogConfig.Config = new Dictionary <string, string>()
                {
                    { "max-size", "200m" }
                };
            }

            CreateContainerParameters containerParams = new CreateContainerParameters
            {
                Image        = imageName,
                Env          = environmentVariables,
                ExposedPorts = portMappings?.ToDictionary(p => $"{p.GamePort.Number}/{p.GamePort.Protocol}", p => new EmptyStruct()),
                HostConfig   = hostConfig,
                WorkingDir   = workingDirectory,
                Cmd          = startCmd
            };

            _logger.LogInformation($"Creating container. Image='{imageName}'");
            CreateContainerResponse response =
                await TaskUtil.TimedExecute(
                    async() => await _dockerClient.Containers.CreateContainerAsync(containerParams).ConfigureAwait(false),
                    _logger,
                    MetricConstants.ContainerStats,
                    MetricConstants.ContainerCreationTime);

            _logger.LogInformation($"Created a container with session host id: {response.ID}");

            return(response.ID);
        }