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

feat: support for entrypoint and enable_ipv6 #50

Merged
merged 2 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ If a feature is missing, please feel free to [create an issue](https://github.co
| [`runtime`](https://docs.docker.com/compose/compose-file/05-services/#runtime) | ✅ | |
| [`security_opt`](https://docs.docker.com/compose/compose-file/05-services/#security_opt) | ✅ | |
| [`command`](https://docs.docker.com/compose/compose-file/05-services/#command) | ✅ | |
| [`entrypoint`](https://docs.docker.com/compose/compose-file/05-services/#entrypoint) | ✅ | |
| [`healthcheck`](https://docs.docker.com/compose/compose-file/05-services/#healthcheck) | ✅ | |
| [`hostname`](https://docs.docker.com/compose/compose-file/05-services/#hostname) | ✅ | |
| [`mac_address`](https://docs.docker.com/compose/compose-file/05-services/#mac_address) | ✅ | |
Expand All @@ -384,6 +385,7 @@ If a feature is missing, please feel free to [create an issue](https://github.co
| [`name`](https://docs.docker.com/compose/compose-file/06-networks/#name) | ✅ |
| [`driver`](https://docs.docker.com/compose/compose-file/06-networks/#driver) | ✅ |
| [`driver_opts`](https://docs.docker.com/compose/compose-file/06-networks/#driver_opts) | ✅ |
| [`enable_ipv6`](https://docs.docker.com/compose/compose-file/06-networks/#enable_ipv6) | ✅ |
| [`ipam`](https://docs.docker.com/compose/compose-file/06-networks/#ipam) | ✅ |
| [`external`](https://docs.docker.com/compose/compose-file/06-networks/#external) | ✅ |
| [`internal`](https://docs.docker.com/compose/compose-file/06-networks/#internal) | ✅ |
Expand Down
13 changes: 7 additions & 6 deletions compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"cmp"
"context"
"encoding/json"
"fmt"
"log"
"path"
Expand Down Expand Up @@ -241,11 +240,7 @@ func healthCheckCommandToString(cmd []string) (string, error) {
case "CMD-SHELL":
return cmd[1], nil
case "CMD":
j, err := json.Marshal(cmd[1:])
if err != nil {
return "", fmt.Errorf("failed to convert %v to JSON: %w", cmd[1:], err)
}
return string(j), nil
return sliceToStringArray(cmd[1:]), nil
}
panic("unreachable")
}
Expand Down Expand Up @@ -330,6 +325,9 @@ func (g *Generator) buildNixContainer(service types.ServiceConfig, networkMap ma
if !service.Command.IsZero() {
c.Command = service.Command
}
if entrypoint := service.Entrypoint; !entrypoint.IsZero() {
c.ExtraOptions = append(c.ExtraOptions, fmt.Sprintf("--entrypoint=%s", sliceToStringArray(entrypoint)))
}

// Figure out explicit dependencies for this container.
//
Expand Down Expand Up @@ -745,6 +743,9 @@ func (g *Generator) buildNixNetworks(composeProject *types.Project) ([]*NixNetwo
if network.Internal {
n.ExtraOptions = append(n.ExtraOptions, "--internal")
}
if enableIPv6 := network.EnableIPv6; enableIPv6 != nil && *enableIPv6 {
n.ExtraOptions = append(n.ExtraOptions, "--ipv6")
}

// IPAM configuration.
// https://docs.docker.com/compose/compose-file/06-networks/#ipam
Expand Down
11 changes: 11 additions & 0 deletions helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ func mapToRepeatedKeyValFlag(flagName string, m map[string]string) []string {
return arr
}

func sliceToStringArray(s []string) string {
b := strings.Builder{}
b.WriteString("[")
for i := range s {
// We purposefully do not use %q to avoid Go's built-in string escaping.
// Otherwise, we'd escape " characters a 2nd time for Nix.
s[i] = fmt.Sprintf(`"%s"`, s[i])
}
return fmt.Sprintf("[%s]", strings.Join(s, ", "))
}

// ReadEnvFiles reads the given set of env files into a list of KEY=VAL entries.
//
// If mergeWithEnv is set, the running env is merged with the provided env files. Any
Expand Down
20 changes: 20 additions & 0 deletions nix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ func TestUpheldBy(t *testing.T) {
runSubtestsWithGenerator(t, g)
}

func TestCommandAndEntrypoint(t *testing.T) {
composePath, envFilePath := getPaths(t, false)
g := &Generator{
Project: NewProject("test"),
Inputs: []string{composePath},
EnvFiles: []string{envFilePath},
}
runSubtestsWithGenerator(t, g)
}

func TestRemoveVolumes(t *testing.T) {
composePath, envFilePath := getPaths(t, true)
g := &Generator{
Expand Down Expand Up @@ -254,6 +264,16 @@ func TestNetworkAndVolumeNames(t *testing.T) {
runSubtestsWithGenerator(t, g)
}

func TestNetworkSettings(t *testing.T) {
composePath, _ := getPaths(t, false)
g := &Generator{
Project: NewProject("test"),
Inputs: []string{composePath},
GenerateUnusedResources: true,
}
runSubtestsWithGenerator(t, g)
}

func TestRelativeServiceVolumes(t *testing.T) {
composePath, _ := getPaths(t, false)
g := &Generator{
Expand Down
39 changes: 39 additions & 0 deletions nixos-test/docker-compose.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,32 @@
virtualisation.oci-containers.backend = "docker";

# Containers
virtualisation.oci-containers.containers."myproject-entrypoint" = {
image = "docker.io/library/nginx:stable-alpine-slim";
log-driver = "journald";
extraOptions = [
"--entrypoint=[\"echo\", \"abc\"]"
"--network-alias=entrypoint"
"--network=myproject_default"
];
};
systemd.services."docker-myproject-entrypoint" = {
serviceConfig = {
Restart = lib.mkOverride 90 "no";
};
after = [
"docker-network-myproject_default.service"
];
requires = [
"docker-network-myproject_default.service"
];
partOf = [
"docker-compose-myproject-root.target"
];
wantedBy = [
"docker-compose-myproject-root.target"
];
};
virtualisation.oci-containers.containers."myproject-no-restart" = {
image = "docker.io/library/nginx:stable-alpine-slim";
log-driver = "journald";
Expand Down Expand Up @@ -150,6 +176,19 @@
};

# Networks
systemd.services."docker-network-myproject_another" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "docker network rm -f myproject_another";
};
script = ''
docker network inspect myproject_another || docker network create myproject_another --driver=bridge --ipv6
'';
partOf = [ "docker-compose-myproject-root.target" ];
wantedBy = [ "docker-compose-myproject-root.target" ];
};
systemd.services."docker-network-myproject_default" = {
path = [ pkgs.docker ];
serviceConfig = {
Expand Down
8 changes: 8 additions & 0 deletions nixos-test/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ services:
restart: on-failure:3
no-restart:
image: docker.io/library/nginx:stable-alpine-slim
entrypoint:
image: docker.io/library/nginx:stable-alpine-slim
entrypoint:
- echo
- abc

networks:
something:
Expand All @@ -53,6 +58,9 @@ networks:
labels:
- "test-label=okay"
- "escape-me=''hello''"
another:
driver: bridge
enable_ipv6: true

volumes:
storage:
Expand Down
39 changes: 39 additions & 0 deletions nixos-test/podman-compose.nix
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,32 @@
virtualisation.oci-containers.backend = "podman";

# Containers
virtualisation.oci-containers.containers."myproject-entrypoint" = {
image = "docker.io/library/nginx:stable-alpine-slim";
log-driver = "journald";
extraOptions = [
"--entrypoint=[\"echo\", \"abc\"]"
"--network-alias=entrypoint"
"--network=myproject_default"
];
};
systemd.services."podman-myproject-entrypoint" = {
serviceConfig = {
Restart = lib.mkOverride 90 "no";
};
after = [
"podman-network-myproject_default.service"
];
requires = [
"podman-network-myproject_default.service"
];
partOf = [
"podman-compose-myproject-root.target"
];
wantedBy = [
"podman-compose-myproject-root.target"
];
};
virtualisation.oci-containers.containers."myproject-no-restart" = {
image = "docker.io/library/nginx:stable-alpine-slim";
log-driver = "journald";
Expand Down Expand Up @@ -152,6 +178,19 @@
};

# Networks
systemd.services."podman-network-myproject_another" = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "podman network rm -f myproject_another";
};
script = ''
podman network inspect myproject_another || podman network create myproject_another --driver=bridge --ipv6
'';
partOf = [ "podman-compose-myproject-root.target" ];
wantedBy = [ "podman-compose-myproject-root.target" ];
};
systemd.services."podman-network-myproject_default" = {
path = [ pkgs.podman ];
serviceConfig = {
Expand Down
7 changes: 5 additions & 2 deletions nixos-test/update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ bin/compose2nix \
-output=nixos-test/docker-compose.nix \
-check_systemd_mounts \
-include_env_files=true \
-generate_unused_resources=true \
-use_upheld_by
bin/compose2nix \
-runtime=podman \
-inputs=nixos-test/docker-compose.yml \
-output=nixos-test/podman-compose.nix \
-check_systemd_mounts \
-use_upheld_by \
-include_env_files=true
-include_env_files=true \
-generate_unused_resources=true \
-use_upheld_by

3 changes: 2 additions & 1 deletion template.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ func toNixValue(v any) any {
func toNixList(s []string) string {
b := strings.Builder{}
for i, e := range s {
b.WriteString(fmt.Sprintf("%q", escapeNixString(e)))
// We purposefully do not use %q to avoid Go's built-in string escaping.
b.WriteString(fmt.Sprintf(`"%s"`, escapeNixString(e)))
if i < len(s)-1 {
b.WriteString(" ")
}
Expand Down
2 changes: 1 addition & 1 deletion templates/container.nix.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ virtualisation.oci-containers.containers."{{.Name}}" = {
];
{{- end}}

{{- if .Command}}
{{- if ne .Command nil}}
cmd = {{toNixList .Command}};
{{- end}}

Expand Down
2 changes: 1 addition & 1 deletion testdata/TestBasic.docker.nix
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
user = "1000:1000";
log-driver = "journald";
extraOptions = [
"--health-cmd=[\"curl\",\"-f\",\"http://localhost\"]"
"--health-cmd=[\"curl\", \"-f\", \"http://localhost\"]"
"--health-interval=1m30s"
"--health-retries=3"
"--health-start-period=40s"
Expand Down
2 changes: 1 addition & 1 deletion testdata/TestBasic.podman.nix
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
user = "1000:1000";
log-driver = "journald";
extraOptions = [
"--health-cmd=[\"curl\",\"-f\",\"http://localhost\"]"
"--health-cmd=[\"curl\", \"-f\", \"http://localhost\"]"
"--health-interval=1m30s"
"--health-retries=3"
"--health-start-interval=5s"
Expand Down
2 changes: 1 addition & 1 deletion testdata/TestBasicAutoFormat.docker.nix
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
user = "1000:1000";
log-driver = "journald";
extraOptions = [
"--health-cmd=[\"curl\",\"-f\",\"http://localhost\"]"
"--health-cmd=[\"curl\", \"-f\", \"http://localhost\"]"
"--health-interval=1m30s"
"--health-retries=3"
"--health-start-period=40s"
Expand Down
2 changes: 1 addition & 1 deletion testdata/TestBasicAutoFormat.podman.nix
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
user = "1000:1000";
log-driver = "journald";
extraOptions = [
"--health-cmd=[\"curl\",\"-f\",\"http://localhost\"]"
"--health-cmd=[\"curl\", \"-f\", \"http://localhost\"]"
"--health-interval=1m30s"
"--health-retries=3"
"--health-start-interval=5s"
Expand Down
17 changes: 17 additions & 0 deletions testdata/TestCommandAndEntrypoint.compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
both:
image: nginx:latest
command: ["ls", "-la", "\"escape me please\""]
entrypoint:
["nginx", "-g", "daemon off;", "-c", "/etc/config/nginx/conf/nginx.conf"]
string:
image: nginx:latest
entrypoint: "ENV_VAR=$${ABC} bash /abc.sh"
empty-command-and-entrypoint:
image: nginx:latest
command: []
entrypoint: []
"null-command-and-entrypoint":
image: nginx:latest
command: null
entrypoint: null
Loading
Loading