// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package mock import ( "fmt" "time" "github.com/hashicorp/nomad/helper/envoy" "github.com/hashicorp/nomad/helper/pointer" "github.com/hashicorp/nomad/helper/uuid" "github.com/hashicorp/nomad/nomad/structs" ) // ConnectJob adds a Connect proxy sidecar group service to mock.Job. // // Note this does *not* include the Job.Register mutation that inserts the // associated Sidecar Task (nor the hook that configures envoy as the default). func ConnectJob() *structs.Job { job := Job() tg := job.TaskGroups[0] tg.Services = []*structs.Service{{ Name: "testconnect", PortLabel: "9999", Connect: &structs.ConsulConnect{ SidecarService: new(structs.ConsulSidecarService), }, }} tg.Networks = structs.Networks{{ Mode: "bridge", // always bridge ... for now? }} return job } func ConnectNativeJob(mode string) *structs.Job { job := Job() tg := job.TaskGroups[0] tg.Networks = []*structs.NetworkResource{{ Mode: mode, }} tg.Services = []*structs.Service{{ Name: "test_connect_native", PortLabel: "9999", Connect: &structs.ConsulConnect{ Native: true, }, }} tg.Tasks = []*structs.Task{{ Name: "native_task", }} return job } // ConnectIngressGatewayJob creates a structs.Job that contains the definition // of a Consul Ingress Gateway service. The mode is the name of the network // mode assumed by the task group. If inject is true, a corresponding Task is // set on the group's Tasks (i.e. what the job would look like after job mutation). func ConnectIngressGatewayJob(mode string, inject bool) *structs.Job { job := Job() tg := job.TaskGroups[0] tg.Networks = []*structs.NetworkResource{{ Mode: mode, }} tg.Services = []*structs.Service{{ Name: "my-ingress-service", PortLabel: "9999", Connect: &structs.ConsulConnect{ Gateway: &structs.ConsulGateway{ Proxy: &structs.ConsulGatewayProxy{ ConnectTimeout: pointer.Of(3 * time.Second), EnvoyGatewayBindAddresses: make(map[string]*structs.ConsulGatewayBindAddress), }, Ingress: &structs.ConsulIngressConfigEntry{ Listeners: []*structs.ConsulIngressListener{{ Port: 2000, Protocol: "tcp", Services: []*structs.ConsulIngressService{{ Name: "service1", }}, }}, }, }, }, }} tg.Tasks = nil // some tests need to assume the gateway proxy task has already been injected if inject { tg.Tasks = []*structs.Task{{ Name: fmt.Sprintf("%s-%s", structs.ConnectIngressPrefix, "my-ingress-service"), Kind: structs.NewTaskKind(structs.ConnectIngressPrefix, "my-ingress-service"), Driver: "docker", Config: make(map[string]interface{}), ShutdownDelay: 5 * time.Second, LogConfig: &structs.LogConfig{ MaxFiles: 2, MaxFileSizeMB: 2, }, }} } return job } // ConnectTerminatingGatewayJob creates a structs.Job that contains the definition // of a Consul Terminating Gateway service. The mode is the name of the network mode // assumed by the task group. If inject is true, a corresponding task is set on the // group's Tasks (i.e. what the job would look like after mutation). func ConnectTerminatingGatewayJob(mode string, inject bool) *structs.Job { job := Job() tg := job.TaskGroups[0] tg.Networks = []*structs.NetworkResource{{ Mode: mode, }} tg.Services = []*structs.Service{{ Name: "my-terminating-service", PortLabel: "9999", Connect: &structs.ConsulConnect{ Gateway: &structs.ConsulGateway{ Proxy: &structs.ConsulGatewayProxy{ ConnectTimeout: pointer.Of(3 * time.Second), EnvoyGatewayBindAddresses: make(map[string]*structs.ConsulGatewayBindAddress), }, Terminating: &structs.ConsulTerminatingConfigEntry{ Services: []*structs.ConsulLinkedService{{ Name: "service1", CAFile: "/ssl/ca_file", CertFile: "/ssl/cert_file", KeyFile: "/ssl/key_file", SNI: "sni-name", }}, }, }, }, }} tg.Tasks = nil // some tests need to assume the gateway proxy task has already been injected if inject { tg.Tasks = []*structs.Task{{ Name: fmt.Sprintf("%s-%s", structs.ConnectTerminatingPrefix, "my-terminating-service"), Kind: structs.NewTaskKind(structs.ConnectTerminatingPrefix, "my-terminating-service"), Driver: "docker", Config: make(map[string]interface{}), ShutdownDelay: 5 * time.Second, LogConfig: &structs.LogConfig{ MaxFiles: 2, MaxFileSizeMB: 2, }, }} } return job } // ConnectMeshGatewayJob creates a structs.Job that contains the definition of a // Consul Mesh Gateway service. The mode is the name of the network mode assumed // by the task group. If inject is true, a corresponding task is set on the group's // Tasks (i.e. what the job would look like after job mutation). func ConnectMeshGatewayJob(mode string, inject bool) *structs.Job { job := Job() tg := job.TaskGroups[0] tg.Networks = []*structs.NetworkResource{{ Mode: mode, }} tg.Services = []*structs.Service{{ Name: "my-mesh-service", PortLabel: "public_port", Connect: &structs.ConsulConnect{ Gateway: &structs.ConsulGateway{ Proxy: &structs.ConsulGatewayProxy{ ConnectTimeout: pointer.Of(3 * time.Second), EnvoyGatewayBindAddresses: make(map[string]*structs.ConsulGatewayBindAddress), }, Mesh: &structs.ConsulMeshConfigEntry{ // nothing to configure }, }, }, }} tg.Tasks = nil // some tests need to assume the gateway task has already been injected if inject { tg.Tasks = []*structs.Task{{ Name: fmt.Sprintf("%s-%s", structs.ConnectMeshPrefix, "my-mesh-service"), Kind: structs.NewTaskKind(structs.ConnectMeshPrefix, "my-mesh-service"), Driver: "docker", Config: make(map[string]interface{}), ShutdownDelay: 5 * time.Second, LogConfig: &structs.LogConfig{ MaxFiles: 2, MaxFileSizeMB: 2, }, }} } return job } func BatchConnectJob() *structs.Job { job := &structs.Job{ Region: "global", ID: fmt.Sprintf("mock-connect-batch-job%s", uuid.Generate()), Name: "mock-connect-batch-job", Namespace: structs.DefaultNamespace, Type: structs.JobTypeBatch, Priority: 50, AllAtOnce: false, Datacenters: []string{"dc1"}, TaskGroups: []*structs.TaskGroup{{ Name: "mock-connect-batch-job", Count: 1, EphemeralDisk: &structs.EphemeralDisk{SizeMB: 150}, Networks: []*structs.NetworkResource{{ Mode: "bridge", }}, Tasks: []*structs.Task{{ Name: "connect-proxy-testconnect", Kind: "connect-proxy:testconnect", Driver: "mock_driver", Config: map[string]interface{}{ "run_for": "500ms", }, LogConfig: structs.DefaultLogConfig(), Resources: &structs.Resources{ CPU: 500, MemoryMB: 256, Networks: []*structs.NetworkResource{{ MBits: 50, DynamicPorts: []structs.Port{{Label: "port1"}}, }}, }, }}, Services: []*structs.Service{{ Name: "testconnect", }}, }}, Meta: map[string]string{"owner": "shoenig"}, Status: structs.JobStatusPending, Version: 0, CreateIndex: 42, ModifyIndex: 99, JobModifyIndex: 99, } job.Canonicalize() return job } func ConnectSidecarTask() *structs.Task { return &structs.Task{ Name: "mysidecar-sidecar-task", Driver: "docker", User: "nobody", Config: map[string]interface{}{ "image": envoy.SidecarConfigVar, }, Env: nil, Resources: &structs.Resources{ CPU: 150, MemoryMB: 350, }, Kind: structs.NewTaskKind(structs.ConnectProxyPrefix, "mysidecar"), } } // ConnectAlloc adds a Connect proxy sidecar group service to mock.Alloc. func ConnectAlloc() *structs.Allocation { alloc := Alloc() alloc.Job = ConnectJob() alloc.AllocatedResources.Shared.Networks = []*structs.NetworkResource{ { Mode: "bridge", IP: "10.0.0.1", DynamicPorts: []structs.Port{ { Label: "connect-proxy-testconnect", Value: 9999, To: 9999, }, }, }, } return alloc } // ConnectNativeAlloc creates an alloc with a connect native task. func ConnectNativeAlloc(mode string) *structs.Allocation { alloc := Alloc() alloc.Job = ConnectNativeJob(mode) alloc.AllocatedResources.Shared.Networks = []*structs.NetworkResource{{ Mode: mode, IP: "10.0.0.1", }} return alloc } func ConnectIngressGatewayAlloc(mode string) *structs.Allocation { alloc := Alloc() alloc.Job = ConnectIngressGatewayJob(mode, true) alloc.AllocatedResources.Shared.Networks = []*structs.NetworkResource{{ Mode: mode, IP: "10.0.0.1", }} return alloc } // BatchConnectAlloc is useful for testing task runner things. func BatchConnectAlloc() *structs.Allocation { alloc := &structs.Allocation{ ID: uuid.Generate(), EvalID: uuid.Generate(), NodeID: "12345678-abcd-efab-cdef-123456789abc", Namespace: structs.DefaultNamespace, TaskGroup: "mock-connect-batch-job", TaskResources: map[string]*structs.Resources{ "connect-proxy-testconnect": { CPU: 500, MemoryMB: 256, }, }, AllocatedResources: &structs.AllocatedResources{ Tasks: map[string]*structs.AllocatedTaskResources{ "connect-proxy-testconnect": { Cpu: structs.AllocatedCpuResources{CpuShares: 500}, Memory: structs.AllocatedMemoryResources{MemoryMB: 256}, }, }, Shared: structs.AllocatedSharedResources{ Networks: []*structs.NetworkResource{{ Mode: "bridge", IP: "10.0.0.1", DynamicPorts: []structs.Port{{ Label: "connect-proxy-testconnect", Value: 9999, To: 9999, }}, }}, DiskMB: 0, }, }, Job: BatchConnectJob(), DesiredStatus: structs.AllocDesiredStatusRun, ClientStatus: structs.AllocClientStatusPending, } alloc.JobID = alloc.Job.ID return alloc } func BatchAlloc() *structs.Allocation { alloc := &structs.Allocation{ ID: uuid.Generate(), EvalID: uuid.Generate(), NodeID: "12345678-abcd-efab-cdef-123456789abc", Namespace: structs.DefaultNamespace, TaskGroup: "web", // TODO Remove once clientv2 gets merged Resources: &structs.Resources{ CPU: 500, MemoryMB: 256, DiskMB: 150, Networks: []*structs.NetworkResource{ { Device: "eth0", IP: "192.168.0.100", ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}}, MBits: 50, DynamicPorts: []structs.Port{{Label: "http"}}, }, }, }, TaskResources: map[string]*structs.Resources{ "web": { CPU: 500, MemoryMB: 256, Networks: []*structs.NetworkResource{ { Device: "eth0", IP: "192.168.0.100", ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}}, MBits: 50, DynamicPorts: []structs.Port{{Label: "http", Value: 9876}}, }, }, }, }, SharedResources: &structs.Resources{ DiskMB: 150, }, AllocatedResources: &structs.AllocatedResources{ Tasks: map[string]*structs.AllocatedTaskResources{ "web": { Cpu: structs.AllocatedCpuResources{ CpuShares: 500, }, Memory: structs.AllocatedMemoryResources{ MemoryMB: 256, }, Networks: []*structs.NetworkResource{ { Device: "eth0", IP: "192.168.0.100", ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}}, MBits: 50, DynamicPorts: []structs.Port{{Label: "http", Value: 9876}}, }, }, }, }, Shared: structs.AllocatedSharedResources{ DiskMB: 150, }, }, Job: BatchJob(), DesiredStatus: structs.AllocDesiredStatusRun, ClientStatus: structs.AllocClientStatusPending, } alloc.JobID = alloc.Job.ID return alloc }