From a6f6384b719e2b9f612e763e26240dac1e6cbeba Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Fri, 17 May 2024 15:26:09 +0100 Subject: [PATCH] Permit Consul Connect Gateways to be used with podman (#20611) * Permit Consul Connect Gateways to be used with podman Enable use of Consul Connect Gateways (ingresss/terminating/mesh) with podman task driver. task driver for Connect-enabled tasks for sidecar services which used podman if any other task in the same task group was using podman or fell back to docker otherwise. That PR did not consider consul connect gateways, which remained hardcoded to using docker task driver always. This change applies the same heuristic also to gateway tasks, enabling use of podman. Limitations: The heuristic only works where the task group containing the gateway also contains a podman task. Therefore it does not work for the ingress example in the docs (https://developer.hashicorp.com/nomad/docs/job-specification/gateway#ingress-gateway) which uses connect native and requires the gateway be in a separate task. * cl: add cl for connect gateway podman autodetect * connect: add test ensuring we guess podman for gateway when possible --------- Co-authored-by: Seth Hoenig --- .changelog/20611.txt | 3 ++ nomad/job_endpoint_hook_connect.go | 6 ++-- nomad/job_endpoint_hook_connect_test.go | 46 ++++++++++++++++++++----- 3 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 .changelog/20611.txt diff --git a/.changelog/20611.txt b/.changelog/20611.txt new file mode 100644 index 000000000..18282ce97 --- /dev/null +++ b/.changelog/20611.txt @@ -0,0 +1,3 @@ +```release-note:improvement +consul/connect: Attempt autodetection of podman task driver for Connect gateways +``` diff --git a/nomad/job_endpoint_hook_connect.go b/nomad/job_endpoint_hook_connect.go index 7814d1bc9..fd42cb03c 100644 --- a/nomad/job_endpoint_hook_connect.go +++ b/nomad/job_endpoint_hook_connect.go @@ -375,7 +375,7 @@ func groupConnectHook(job *structs.Job, g *structs.TaskGroup) error { customizedTLS := service.Connect.IsCustomizedTLS() task := newConnectGatewayTask(prefix, service.Name, - service.GetConsulClusterName(g), netHost, customizedTLS) + service.GetConsulClusterName(g), groupConnectGuessTaskDriver(g), netHost, customizedTLS) g.Tasks = append(g.Tasks, task) // the connect.sidecar_task block can also be used to configure @@ -494,7 +494,7 @@ func gatewayBindAddressesIngressForBridge(ingress *structs.ConsulIngressConfigEn return addresses } -func newConnectGatewayTask(prefix, service, cluster string, netHost, customizedTls bool) *structs.Task { +func newConnectGatewayTask(prefix, service, cluster string, driver string, netHost, customizedTls bool) *structs.Task { constraints := structs.Constraints{ connectGatewayVersionConstraint(cluster), connectListenerConstraint(cluster), @@ -506,7 +506,7 @@ func newConnectGatewayTask(prefix, service, cluster string, netHost, customizedT // Name is used in container name so must start with '[A-Za-z0-9]' Name: fmt.Sprintf("%s-%s", prefix, service), Kind: structs.NewTaskKind(prefix, service), - Driver: "docker", + Driver: driver, Config: connectGatewayDriverConfig(netHost), ShutdownDelay: 5 * time.Second, LogConfig: &structs.LogConfig{ diff --git a/nomad/job_endpoint_hook_connect_test.go b/nomad/job_endpoint_hook_connect_test.go index 429309f85..ee304665a 100644 --- a/nomad/job_endpoint_hook_connect_test.go +++ b/nomad/job_endpoint_hook_connect_test.go @@ -201,7 +201,7 @@ func TestJobEndpointConnect_groupConnectHook_IngressGateway_BridgeNetwork(t *tes expTG.Tasks = []*structs.Task{ // inject the gateway task newConnectGatewayTask(structs.ConnectIngressPrefix, "my-gateway", - structs.ConsulDefaultCluster, false, true), + structs.ConsulDefaultCluster, "docker", false, true), } expTG.Services[0].Name = "my-gateway" expTG.Tasks[0].Canonicalize(job, expTG) @@ -241,7 +241,7 @@ func TestJobEndpointConnect_groupConnectHook_IngressGateway_HostNetwork(t *testi expTG.Tasks = []*structs.Task{ // inject the gateway task newConnectGatewayTask(structs.ConnectIngressPrefix, "my-gateway", - structs.ConsulDefaultCluster, true, false), + structs.ConsulDefaultCluster, "docker", true, false), } expTG.Services[0].Name = "my-gateway" expTG.Tasks[0].Canonicalize(job, expTG) @@ -258,6 +258,36 @@ func TestJobEndpointConnect_groupConnectHook_IngressGateway_HostNetwork(t *testi require.Exactly(t, expTG, job.TaskGroups[0]) } +func TestJobEndpointConnect_groupConnectHook_IngressGateway_GuessPodman(t *testing.T) { + ci.Parallel(t) + + // Test that the injected gateway task makes use of the podman driver if there + // is another task in the group that uses podman. + job := mock.ConnectIngressGatewayJob("Host", false) + job.Meta = map[string]string{"gateway_name": "my-gateway"} + job.TaskGroups[0].Services[0].Name = "${NOMAD_META_gateway_name}" + + // setup a task using podman + job.TaskGroups[0].Tasks = []*structs.Task{{ + Name: "mytask", + Driver: "podman", + Config: make(map[string]interface{}), + }} + + expTG := job.TaskGroups[0].Copy() + expTG.Tasks = append(expTG.Tasks, + newConnectGatewayTask(structs.ConnectIngressPrefix, "my-gateway", + structs.ConsulDefaultCluster, "podman", false, false), + ) + expTG.Services[0].Name = "my-gateway" + expTG.Tasks[1].Canonicalize(job, expTG) + expTG.Networks[0].Canonicalize() + expTG.Services[0].Connect.Gateway.Proxy = gatewayProxy(expTG.Services[0].Connect.Gateway, "host") + + must.NoError(t, groupConnectHook(job, job.TaskGroups[0])) + must.Eq(t, expTG, job.TaskGroups[0]) +} + func TestJobEndpointConnect_groupConnectHook_IngressGateway_CustomTask(t *testing.T) { ci.Parallel(t) @@ -344,7 +374,7 @@ func TestJobEndpointConnect_groupConnectHook_TerminatingGateway(t *testing.T) { expTG.Tasks = []*structs.Task{ // inject the gateway task newConnectGatewayTask(structs.ConnectTerminatingPrefix, "my-gateway", - structs.ConsulDefaultCluster, false, false), + structs.ConsulDefaultCluster, "docker", false, false), } expTG.Services[0].Name = "my-gateway" expTG.Tasks[0].Canonicalize(job, expTG) @@ -379,7 +409,7 @@ func TestJobEndpointConnect_groupConnectHook_MeshGateway(t *testing.T) { expTG.Tasks = []*structs.Task{ // inject the gateway task newConnectGatewayTask(structs.ConnectMeshPrefix, "my-gateway", - structs.ConsulDefaultCluster, false, false), + structs.ConsulDefaultCluster, "docker", false, false), } expTG.Services[0].Name = "my-gateway" expTG.Services[0].PortLabel = "public_port" @@ -770,7 +800,7 @@ func TestJobEndpointConnect_newConnectGatewayTask_host(t *testing.T) { t.Run("ingress", func(t *testing.T) { task := newConnectGatewayTask(structs.ConnectIngressPrefix, "foo", - structs.ConsulDefaultCluster, true, false) + structs.ConsulDefaultCluster, "docker", true, false) must.Eq(t, "connect-ingress-foo", task.Name) must.Eq(t, "connect-ingress:foo", string(task.Kind)) must.Eq(t, "${attr.consul.version}", task.Constraints[0].LTarget) @@ -781,7 +811,7 @@ func TestJobEndpointConnect_newConnectGatewayTask_host(t *testing.T) { t.Run("terminating", func(t *testing.T) { task := newConnectGatewayTask(structs.ConnectTerminatingPrefix, "bar", - structs.ConsulDefaultCluster, true, false) + structs.ConsulDefaultCluster, "docker", true, false) must.Eq(t, "connect-terminating-bar", task.Name) must.Eq(t, "connect-terminating:bar", string(task.Kind)) must.Eq(t, "${attr.consul.version}", task.Constraints[0].LTarget) @@ -793,7 +823,7 @@ func TestJobEndpointConnect_newConnectGatewayTask_host(t *testing.T) { // this case can only happen on ENT but gets run in CE code t.Run("terminating nondefault (ENT)", func(t *testing.T) { task := newConnectGatewayTask(structs.ConnectTerminatingPrefix, "bar", - "nondefault", true, false) + "nondefault", "docker", true, false) must.Eq(t, "connect-terminating-bar", task.Name) must.Eq(t, "connect-terminating:bar", string(task.Kind)) must.Eq(t, "${attr.consul.nondefault.version}", task.Constraints[0].LTarget) @@ -807,7 +837,7 @@ func TestJobEndpointConnect_newConnectGatewayTask_bridge(t *testing.T) { ci.Parallel(t) task := newConnectGatewayTask(structs.ConnectIngressPrefix, "service1", - structs.ConsulDefaultCluster, false, false) + structs.ConsulDefaultCluster, "docker", false, false) require.NotContains(t, task.Config, "network_mode") }