Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Expose published host ports of a container #196

Closed
pdevito3 opened this issue Aug 14, 2021 · 5 comments
Closed

[Feature Request] Expose published host ports of a container #196

pdevito3 opened this issue Aug 14, 2021 · 5 comments
Assignees
Labels
enhancement under-investigation A investigation is made around the issue waiting-for-feedback Waiting for someone to give feedback until this issue can be brought further.
Milestone

Comments

@pdevito3
Copy link

Hey there, huge fan of the library! Very well done.

Wondering if it would be possible to expose the host ports for a container? I'm able to get the exposed ports, but not the host ones.

For example, if i did this:

var container = new Builder().UseContainer()
                    .WithName("MyName")
                    .UseImage($"{DB_IMAGE}:{DB_IMAGE_TAG}")
                    .ExposePort(freePort, 5432)
                    .WithEnvironment(
                        "POSTGRES_PASSWORD={DB_PASSWORD}",
                        $"POSTGRES_DB={DB_NAME}",
                        $"POSTGRES_PASSWORD={DB_PASSWORD}")
                    .WaitForPort("5432/tcp", 30000 /*30s*/)
                    .MountVolume(volume, "/var/lib/postgresql/data", MountType.ReadWrite)
                    .Build();

I'd like to be able to get the port for that container with something along the lines of this or whatever else makes sense

var docker = hosts.FirstOrDefault(x => x.IsNative) ?? hosts.FirstOrDefault(x => x.Name == "default");
var existingContainer = docker?.GetContainers().FirstOrDefault(c => c.Name == DB_CONTAINER_NAME);

// this should return whatever `freePort` was from above
var ports = existingContainer.GetConfiguration().Config.HostPorts.FirstOrDefault();
@mariotoffia mariotoffia self-assigned this Aug 16, 2021
@mariotoffia mariotoffia added enhancement under-investigation A investigation is made around the issue labels Aug 16, 2021
@mariotoffia mariotoffia added this to the 4.0.0 milestone Aug 16, 2021
@mariotoffia mariotoffia added the waiting-for-feedback Waiting for someone to give feedback until this issue can be brought further. label Aug 16, 2021
@mariotoffia
Copy link
Owner

Hi @pdevito3, I'm really glad to hear that you like FluentDocker :)!

Just to make sure that I understand what you want. It is not this you want to achieve?

container.ToHostExposedEndpoint("5432/tcp")

That may be used to render the endpoint.

 using (var container =
          Fd.UseContainer()
            .UseImage("nginx:1.13.6-alpine")
            .ExposePort(80)
            .WaitForPort("80/tcp", 30000 /*30s*/)
            .Build()
            .Start())
        {
          var response = $"http://{container.ToHostExposedEndpoint("80/tcp")}".Wget().Result;
          Console.WriteLine(response);
        }
      }
    }

If you want some specific network you can use this.

For example

using (var nw = Fd.UseNetwork("unit-test-nw")
        .UseSubnet("10.18.0.0/16").Build())
      {
        using (
          var container =
            Fd.UseContainer()
              .WithName("mycontainer")
              .UseImage("postgres:9.6-alpine")
              .WithEnvironment("POSTGRES_PASSWORD=mysecretpassword")
              .ExposePort(5432)
              .UseNetwork(nw)
              .UseIpV4("10.18.0.22")
              .WaitForPort("5432/tcp", 30000 /*30s*/)
              .Build()
              .Start())
        {
          var ip = container.GetConfiguration().NetworkSettings.Networks["unit-test-nw"].IPAddress;
          Assert.AreEqual("10.18.0.22", ip);
        }
      }
    }

Cheers,
Mario :)

@pdevito3
Copy link
Author

pdevito3 commented Aug 17, 2021

Ah, existingContainer.ToHostExposedEndpoint("5432/tcp").Port; did it for me!

Thanks for the insight. Fwiw, it might be nice to expose this on the config as well and document this possibility here. Docs seemed a little light on getting container info, though I was able to figure it out pretty quickly save for the above.

Regardless, thanks again for putting this library together! Chopping down my Docker.Net based file significantly and making it much easier to read.

@pdevito3
Copy link
Author

reopening in case you want to track this as a new feature for a simplified api

@pdevito3 pdevito3 reopened this Aug 17, 2021
@mariotoffia
Copy link
Owner

mariotoffia commented Aug 17, 2021

Hi and thanks for reporting this! :)

However, I have a hard time making this API any easier (however the zero documentation on Model/Container needs to be fixed :)).

Beneath the

container.ToHostExposedEndpoint("5432/tcp")

there's more than just looking up the container for this port. It uses a default or custom, resolver to resolve the endpoint and many have provided their own to match their use case. Have a look at ContainerExtensions and NetworkExtensions (ToHostExposedEndpoint / ToHostPortCustomResolver) for how the endpoint is being resolved.

Having said that, I would be really glad if you had a suggestion to simplify the API to get the exposed IPEndPoint.

Cheers,
Mario :)

Default resolver looks like this

   public static IPEndPoint ToHostPortCustomResolver(
     this Dictionary<string, HostIpEndpoint[]> ports,
     Func<Dictionary<string, HostIpEndpoint[]>, string, Uri, IPEndPoint> customResolver,
     string portAndProto,
     Uri dockerUri = null)
   {

     if (customResolver != null)
     {
       var ep = customResolver.Invoke(ports, portAndProto, dockerUri);

       if (ep != null)
       {
         return ep;
       }

     }

     if (null == ports || string.IsNullOrEmpty(portAndProto))
       return null;

     if (!ports.TryGetValue(portAndProto, out var endpoints))
       return null;

     if (null == endpoints || endpoints.Length == 0)
       return null;

     if (CommandExtensions.IsNative())
       return endpoints[0];

     if (CommandExtensions.IsEmulatedNative())
       return CommandExtensions.IsDockerDnsAvailable()
         ? new IPEndPoint(CommandExtensions.EmulatedNativeAddress(), endpoints[0].Port)
         : new IPEndPoint(IPAddress.Loopback, endpoints[0].Port);

     if (Equals(endpoints[0].Address, IPAddress.Any) && null != dockerUri)
       return new IPEndPoint(IPAddress.Parse(dockerUri.Host), endpoints[0].Port);

     return endpoints[0];
   }

@pdevito3
Copy link
Author

totally fair! i know there's usually more going on under the hood than meets the eye :-)

Doesn't seem worth the lift, so I think as long as this is documented with an example then that would have been sufficient for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement under-investigation A investigation is made around the issue waiting-for-feedback Waiting for someone to give feedback until this issue can be brought further.
Projects
None yet
Development

No branches or pull requests

2 participants