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

Add podman support #300

Open
atrauzzi opened this issue Sep 13, 2023 · 8 comments
Open

Add podman support #300

atrauzzi opened this issue Sep 13, 2023 · 8 comments

Comments

@atrauzzi
Copy link

atrauzzi commented Sep 13, 2023

Given Dockers decline in reputation over the last while, there's a lot of movement towards podman.

I just tried using this library to run a container on my local podman (linux, Fedora, no Windows!) environment and got the following:

Unhandled exception. Newtonsoft.Json.JsonSerializationException: Error converting value "" to type 'Ductus.FluentDocker.Model.Containers.HealthState'. Path 'State.Health.Status', line 22, position 32.
 ---> System.ArgumentException: Must specify valid information for parsing in the string.
   at Newtonsoft.Json.Utilities.EnumUtils.ParseEnum(Type enumType, NamingStrategy namingStrategy, String value, Boolean disallowNumber)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
   at Ductus.FluentDocker.Executors.Parsers.ClientContainerInspectCommandResponder.Process(ProcessExecutionResult response)
   at Ductus.FluentDocker.Executors.ProcessExecutor`2.Execute()
   at Ductus.FluentDocker.Commands.Client.InspectContainer(DockerUri host, String id, ICertificatePaths certificates)
   at Ductus.FluentDocker.Services.Impl.DockerHostService.Create(String image, Boolean forcePull, ContainerCreateParams prms, Boolean stopOnDispose, Boolean deleteOnDispose, Boolean deleteVolumeOnDispose, Boolean deleteNamedVolumeOnDispose, String command, String[] args, Func`4 customEndpointResolver)
   at Ductus.FluentDocker.Builders.ContainerBuilder.Build()

Anyway, I run containers all the time for local development using jetbrains tooling and CLI. I have the docker and docker-compose commands available, mapped to their fully API compatible podman equivalents (if it matters).

@Rory-Reid
Copy link

I've just tried playing around with podman too and hit the same thing, but I'm not convinced it is FluentDocker's fault.

This failure occurs when parsing the result of docker inspect, and it turns out I cannot manually create and inspect a single container on my machine and get a valid health state (I'm on macOS if that's useful), they all look like this:

"Health": {
  "Status": "",
  "FailingStreak": 0,
  "Log": null
}

FluentDocker is trying to parse Status to an enum and not defaulting empty string to unknown, which I guess it could but then the .WaitForHealthy() builder function would fail since it looks like it relies on that? I never actually rely on that command it turns out which would work for me but something still feels off.

Not had much luck finding out why this is the case in podman yet, and don't have docker available to compare with just yet.

@atrauzzi
Copy link
Author

Running on Fedora and [podman|docker] inspect works for me.

Your issue might be mac specific. I'd still say this library needs to investigate given that the JetBrains container tooling is working flawlessely.

@Rory-Reid
Copy link

[podman|docker] inspect works for me too? It just doesn't give the exact same format output as docker does as far as I can tell, which is why the parsing falls down here. Your exception and stack trace look the same as what I experienced, I could be missing something but it all reads like what I reproduced and observed. Found similar problems on my linux laptop too.

Nonetheless, I've dumped my podman inspect output into a unit test here to demonstrate the failure: https://github.com/Rory-Reid/FluentDocker/tree/reproduce-missing-health-status

There's two issues with it. State.Health.Status and Config.Entrypoint don't parse, I'm going to see if I can suggest a fix for those, and explore if there's other issues.

@Rory-Reid
Copy link

Definitely more issues once you get past that, failing on the following command:

docker network ls --no-trunc --format "{{.ID}};{{.Name}};{{.Driver}};{{.Source}};{{.IPv6}};{{.Internal}};{{.CreatedAt}}"

Several of these properties (eg Source, IPv6, CreatedAt) are not available on either machine I've tested with, and the --format fails very ungracefully when that happens. Within FluentDocker, ID and Name are the only ones currently used, so defensively we could avoid trying to request and parse what we don't need here (though as of now I don't know if this class is public / something you could or would depend on in client code).

Next, it crashes when FluentDocker tries to parse the output of docker top {container id}. This is because the TIME column looks something like:

TIME
0s
0s
0s
0s
0s
0s
0s

And docker's output looks like this:

TIME
00:00:00
00:00:04
00:00:00
01:28:20
00:00:00
00:00:12
00:00:00

and it cannot parse 0s to a valid TimeSpan

Once again, it looks like this is parsed by FluentDocker but without any internal usage, so could be removed for a more defensive approach to parsing output. It feels a bit rude to go chopping all of this away to support podman here, and ideally podman output would be truly interchangeable with docker output and we'd have none of these issues, but maybe a case could be made for a more generally defensive approach to FluentDocker which would just so happen to solve the immediate problems - remove unused code, and only parse what is strictly needed today?

After making all of these amendments in a local branch, FluentDocker appears to work for me, with podman v4.6.2, within the scope of my limited use in test projects (3 different containers). I'm sure there's a lot more edge cases beyond this.

@Rory-Reid
Copy link

Have published #303 as a hopefully amicable first-pass support for podman, obviously subject to the maintainer actually wanting to bring this in.

@mariotoffia
Copy link
Owner

Nice work @Rory-Reid - I greatly appreciate it!

I had one comment, could you please check it out?

Cheers

@atrauzzi
Copy link
Author

Any chance this can progress?

@mariotoffia
Copy link
Owner

@atrauzzi sorry, yes, I'll have a look this weekend and make sure to get this going!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants