From aff6339e36a03f70c5c147e6ea138bac53e0fb08 Mon Sep 17 00:00:00 2001 From: James Rasell Date: Thu, 16 Sep 2021 08:13:09 +0200 Subject: [PATCH] allow configuration of Docker hostnames in bridge mode (#11173) Add a new hostname string parameter to the network block which allows operators to specify the hostname of the network namespace. Changing this causes a destructive update to the allocation and it is omitted if empty from API responses. This parameter also supports interpolation. In order to have a hostname passed as a configuration param when creating an allocation network, the CreateNetwork func of the DriverNetworkManager interface needs to be updated. In order to minimize the disruption of future changes, rather than add another string func arg, the function now accepts a request struct along with the allocID param. The struct has the hostname as a field. The in-tree implementations of DriverNetworkManager.CreateNetwork have been modified to account for the function signature change. In updating for the change, the enhancement of adding hostnames to network namespaces has also been added to the Docker driver, whilst the default Linux manager does not current implement it. --- api/resources.go | 1 + client/allocrunner/alloc_runner_hooks.go | 12 +- client/allocrunner/network_hook.go | 66 ++- client/allocrunner/network_hook_test.go | 10 +- client/allocrunner/network_manager_linux.go | 25 +- .../allocrunner/network_manager_linux_test.go | 86 ++++ client/taskenv/network.go | 29 ++ client/taskenv/network_test.go | 45 ++ command/agent/job_endpoint.go | 9 +- command/agent/job_endpoint_test.go | 10 +- drivers/docker/network.go | 47 +- drivers/docker/network_test.go | 66 +++ .../inputs/docker_bridged_hostname.nomad | 24 + ...ocker_bridged_hostname_interpolation.nomad | 24 + e2e/networking/networking.go | 82 +++- go.mod | 1 + jobspec/parse_network.go | 1 + .../tg-network-with-hostname.hcl | 34 ++ nomad/plan_normalization_test.go | 2 +- nomad/structs/diff_test.go | 30 +- nomad/structs/structs.go | 23 +- nomad/structs/structs_test.go | 86 +++- plugins/drivers/driver.go | 11 +- plugins/drivers/proto/driver.pb.go | 445 +++++++++--------- plugins/drivers/proto/driver.proto | 3 + plugins/drivers/server.go | 3 +- plugins/drivers/testutils/testing.go | 6 +- plugins/drivers/utils.go | 9 + plugins/drivers/utils_test.go | 33 ++ scheduler/util.go | 4 + scheduler/util_test.go | 10 + 31 files changed, 947 insertions(+), 290 deletions(-) create mode 100644 client/taskenv/network.go create mode 100644 client/taskenv/network_test.go create mode 100644 drivers/docker/network_test.go create mode 100644 e2e/networking/inputs/docker_bridged_hostname.nomad create mode 100644 e2e/networking/inputs/docker_bridged_hostname_interpolation.nomad create mode 100644 jobspec/test-fixtures/tg-network-with-hostname.hcl diff --git a/api/resources.go b/api/resources.go index d9bd49476aed..b5ada2d9ec14 100644 --- a/api/resources.go +++ b/api/resources.go @@ -119,6 +119,7 @@ type NetworkResource struct { DNS *DNSConfig `hcl:"dns,block"` ReservedPorts []Port `hcl:"reserved_ports,block"` DynamicPorts []Port `hcl:"port,block"` + Hostname string `hcl:"hostname,optional"` // COMPAT(0.13) // XXX Deprecated. Please do not use. The field will be removed in Nomad diff --git a/client/allocrunner/alloc_runner_hooks.go b/client/allocrunner/alloc_runner_hooks.go index 07a184ffe422..9624e633c730 100644 --- a/client/allocrunner/alloc_runner_hooks.go +++ b/client/allocrunner/alloc_runner_hooks.go @@ -133,6 +133,14 @@ func (ar *allocRunner) initRunnerHooks(config *clientconfig.Config) error { return fmt.Errorf("failed to initialize network configurator: %v", err) } + // Create a new taskenv.Builder which is used and mutated by networkHook. + envBuilder := taskenv.NewBuilder( + config.Node, ar.Alloc(), nil, config.Region).SetAllocDir(ar.allocDir.AllocDir) + + // Create a taskenv.TaskEnv which is used for read only purposes by the + // newNetworkHook. + builtTaskEnv := envBuilder.Build() + // Create the alloc directory hook. This is run first to ensure the // directory path exists for other hooks. alloc := ar.Alloc() @@ -142,13 +150,13 @@ func (ar *allocRunner) initRunnerHooks(config *clientconfig.Config) error { newUpstreamAllocsHook(hookLogger, ar.prevAllocWatcher), newDiskMigrationHook(hookLogger, ar.prevAllocMigrator, ar.allocDir), newAllocHealthWatcherHook(hookLogger, alloc, hs, ar.Listener(), ar.consulClient), - newNetworkHook(hookLogger, ns, alloc, nm, nc, ar), + newNetworkHook(hookLogger, ns, alloc, nm, nc, ar, builtTaskEnv), newGroupServiceHook(groupServiceHookConfig{ alloc: alloc, consul: ar.consulClient, consulNamespace: alloc.ConsulNamespace(), restarter: ar, - taskEnvBuilder: taskenv.NewBuilder(config.Node, ar.Alloc(), nil, config.Region).SetAllocDir(ar.allocDir.AllocDir), + taskEnvBuilder: envBuilder, networkStatusGetter: ar, logger: hookLogger, }), diff --git a/client/allocrunner/network_hook.go b/client/allocrunner/network_hook.go index 70f82111c6d8..b540d4b5e569 100644 --- a/client/allocrunner/network_hook.go +++ b/client/allocrunner/network_hook.go @@ -5,14 +5,25 @@ import ( "fmt" hclog "github.com/hashicorp/go-hclog" + "github.com/hashicorp/nomad/client/taskenv" "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/plugins/drivers" + "github.com/miekg/dns" ) -// We create a pause container to own the network namespace, and the -// NetworkIsolationSpec we get back from CreateNetwork has this label set as -// the container ID. We'll use this to generate a hostname for the task. -const dockerNetSpecLabelKey = "docker_sandbox_container_id" +const ( + // dockerNetSpecLabelKey is the label added when we create a pause + // container to own the network namespace, and the NetworkIsolationSpec we + // get back from CreateNetwork has this label set as the container ID. + // We'll use this to generate a hostname for the task in the event the user + // did not specify a custom one. Please see dockerNetSpecHostnameKey. + dockerNetSpecLabelKey = "docker_sandbox_container_id" + + // dockerNetSpecHostnameKey is the label added when we create a pause + // container and the task group network include a user supplied hostname + // parameter. + dockerNetSpecHostnameKey = "docker_sandbox_hostname" +) type networkIsolationSetter interface { SetNetworkIsolation(*drivers.NetworkIsolationSpec) @@ -61,6 +72,9 @@ type networkHook struct { // the alloc network has been created networkConfigurator NetworkConfigurator + // taskEnv is used to perform interpolation within the network blocks. + taskEnv *taskenv.TaskEnv + logger hclog.Logger } @@ -69,13 +83,16 @@ func newNetworkHook(logger hclog.Logger, alloc *structs.Allocation, netManager drivers.DriverNetworkManager, netConfigurator NetworkConfigurator, - networkStatusSetter networkStatusSetter) *networkHook { + networkStatusSetter networkStatusSetter, + taskEnv *taskenv.TaskEnv, +) *networkHook { return &networkHook{ isolationSetter: ns, networkStatusSetter: networkStatusSetter, alloc: alloc, manager: netManager, networkConfigurator: netConfigurator, + taskEnv: taskEnv, logger: logger, } } @@ -95,8 +112,24 @@ func (h *networkHook) Prerun() error { return nil } - spec, created, err := h.manager.CreateNetwork(h.alloc.ID) + // Perform our networks block interpolation. + interpolatedNetworks := taskenv.InterpolateNetworks(h.taskEnv, tg.Networks) + + // Interpolated values need to be validated. It is also possible a user + // supplied hostname avoids the validation on job registrations because it + // looks like it includes interpolation, when it doesn't. + if interpolatedNetworks[0].Hostname != "" { + if _, ok := dns.IsDomainName(interpolatedNetworks[0].Hostname); !ok { + return fmt.Errorf("network hostname %q is not a valid DNS name", interpolatedNetworks[0].Hostname) + } + } + + // Our network create request. + networkCreateReq := drivers.NetworkCreateRequest{ + Hostname: interpolatedNetworks[0].Hostname, + } + spec, created, err := h.manager.CreateNetwork(h.alloc.ID, &networkCreateReq) if err != nil { return fmt.Errorf("failed to create network for alloc: %v", err) } @@ -111,18 +144,31 @@ func (h *networkHook) Prerun() error { if err != nil { return fmt.Errorf("failed to configure networking for alloc: %v", err) } - if hostname, ok := spec.Labels[dockerNetSpecLabelKey]; ok { + + // If the driver set the sandbox hostname label, then we will use that + // to set the HostsConfig.Hostname. Otherwise, identify the sandbox + // container ID which will have been used to set the network namespace + // hostname. + if hostname, ok := spec.Labels[dockerNetSpecHostnameKey]; ok { + h.spec.HostsConfig = &drivers.HostsConfig{ + Address: status.Address, + Hostname: hostname, + } + } else if hostname, ok := spec.Labels[dockerNetSpecLabelKey]; ok { + + // the docker_sandbox_container_id is the full ID of the pause + // container, whereas we want the shortened name that dockerd sets + // as the pause container's hostname. if len(hostname) > 12 { - // the docker_sandbox_container_id is the full ID of the pause - // container, whereas we want the shortened name that dockerd - // sets as the pause container's hostname hostname = hostname[:12] } + h.spec.HostsConfig = &drivers.HostsConfig{ Address: status.Address, Hostname: hostname, } } + h.networkStatusSetter.SetNetworkStatus(status) } return nil diff --git a/client/allocrunner/network_hook_test.go b/client/allocrunner/network_hook_test.go index a15084cd36a7..c5dee542c91f 100644 --- a/client/allocrunner/network_hook_test.go +++ b/client/allocrunner/network_hook_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/hashicorp/nomad/client/allocrunner/interfaces" + "github.com/hashicorp/nomad/client/taskenv" "github.com/hashicorp/nomad/helper/testlog" "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/structs" @@ -56,7 +57,7 @@ func TestNetworkHook_Prerun_Postrun(t *testing.T) { destroyCalled := false nm := &testutils.MockDriver{ MockNetworkManager: testutils.MockNetworkManager{ - CreateNetworkF: func(allocID string) (*drivers.NetworkIsolationSpec, bool, error) { + CreateNetworkF: func(allocID string, req *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error) { require.Equal(t, alloc.ID, allocID) return spec, false, nil }, @@ -79,8 +80,10 @@ func TestNetworkHook_Prerun_Postrun(t *testing.T) { } require := require.New(t) + envBuilder := taskenv.NewBuilder(mock.Node(), alloc, nil, alloc.Job.Region) + logger := testlog.HCLogger(t) - hook := newNetworkHook(logger, setter, alloc, nm, &hostNetworkConfigurator{}, statusSetter) + hook := newNetworkHook(logger, setter, alloc, nm, &hostNetworkConfigurator{}, statusSetter, envBuilder.Build()) require.NoError(hook.Prerun()) require.True(setter.called) require.False(destroyCalled) @@ -91,11 +94,10 @@ func TestNetworkHook_Prerun_Postrun(t *testing.T) { setter.called = false destroyCalled = false alloc.Job.TaskGroups[0].Networks[0].Mode = "host" - hook = newNetworkHook(logger, setter, alloc, nm, &hostNetworkConfigurator{}, statusSetter) + hook = newNetworkHook(logger, setter, alloc, nm, &hostNetworkConfigurator{}, statusSetter, envBuilder.Build()) require.NoError(hook.Prerun()) require.False(setter.called) require.False(destroyCalled) require.NoError(hook.Postrun()) require.False(destroyCalled) - } diff --git a/client/allocrunner/network_manager_linux.go b/client/allocrunner/network_manager_linux.go index 0d6ef3e98dc1..a4a08ce29cea 100644 --- a/client/allocrunner/network_manager_linux.go +++ b/client/allocrunner/network_manager_linux.go @@ -26,8 +26,18 @@ func newNetworkManager(alloc *structs.Allocation, driverManager drivermanager.Ma tgNetMode = tg.Networks[0].Mode } + groupIsolationMode := netModeToIsolationMode(tgNetMode) + + // Setting the hostname is only possible where the task groups networking + // mode is group; meaning bridge or none. + if len(tg.Networks) > 0 && + (groupIsolationMode != drivers.NetIsolationModeGroup && tg.Networks[0].Hostname != "") { + return nil, fmt.Errorf("hostname cannot be set on task group using %q networking mode", + groupIsolationMode) + } + // networkInitiator tracks the task driver which needs to create the network - // to check for multiple drivers needing the create the network + // to check for multiple drivers needing to create the network. var networkInitiator string // driverCaps tracks which drivers we've checked capabilities for so as not @@ -80,6 +90,14 @@ func newNetworkManager(alloc *structs.Allocation, driverManager drivermanager.Ma nm = netManager networkInitiator = task.Name + } else if tg.Networks[0].Hostname != "" { + // TODO jrasell: remove once the default linux network manager + // supports setting the hostname in bridged mode. This currently + // indicates only Docker supports this, which is true unless a + // custom driver can which means this check still holds as true as + // we can tell. + // Please see: https://github.com/hashicorp/nomad/issues/11180 + return nil, fmt.Errorf("hostname is not currently supported on driver %s", task.Driver) } // mark this driver's capabilities as checked @@ -92,7 +110,10 @@ func newNetworkManager(alloc *structs.Allocation, driverManager drivermanager.Ma // defaultNetworkManager creates a network namespace for the alloc type defaultNetworkManager struct{} -func (*defaultNetworkManager) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, bool, error) { +// CreateNetwork is the CreateNetwork implementation of the +// drivers.DriverNetworkManager interface function. It does not currently +// support setting the hostname of the network namespace. +func (*defaultNetworkManager) CreateNetwork(allocID string, _ *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error) { netns, err := nsutil.NewNS(allocID) if err != nil { // when a client restarts, the namespace will already exist and diff --git a/client/allocrunner/network_manager_linux_test.go b/client/allocrunner/network_manager_linux_test.go index eab55dc5a2b4..ac2f97c8fdc4 100644 --- a/client/allocrunner/network_manager_linux_test.go +++ b/client/allocrunner/network_manager_linux_test.go @@ -164,6 +164,92 @@ func TestNewNetworkManager(t *testing.T) { err: true, errContains: "want to initiate networking but only one", }, + { + name: "hostname set in bridged mode", + alloc: &structs.Allocation{ + TaskGroup: "group", + Job: &structs.Job{ + TaskGroups: []*structs.TaskGroup{ + { + Name: "group", + Networks: []*structs.NetworkResource{ + { + Mode: "bridge", + Hostname: "foobar", + }, + }, + Tasks: []*structs.Task{ + { + Name: "task1", + Driver: "mustinit1", + Resources: &structs.Resources{}, + }, + }, + }, + }, + }, + }, + mustInit: true, + err: false, + }, + { + name: "hostname set in host mode", + alloc: &structs.Allocation{ + TaskGroup: "group", + Job: &structs.Job{ + TaskGroups: []*structs.TaskGroup{ + { + Name: "group", + Networks: []*structs.NetworkResource{ + { + Mode: "host", + Hostname: "foobar", + }, + }, + Tasks: []*structs.Task{ + { + Name: "task1", + Driver: "group1", + Resources: &structs.Resources{}, + }, + }, + }, + }, + }, + }, + mustInit: false, + err: true, + errContains: `hostname cannot be set on task group using "host" networking mode`, + }, + { + name: "hostname set using exec driver", + alloc: &structs.Allocation{ + TaskGroup: "group", + Job: &structs.Job{ + TaskGroups: []*structs.TaskGroup{ + { + Name: "group", + Networks: []*structs.NetworkResource{ + { + Mode: "bridge", + Hostname: "foobar", + }, + }, + Tasks: []*structs.Task{ + { + Name: "task1", + Driver: "group1", + Resources: &structs.Resources{}, + }, + }, + }, + }, + }, + }, + mustInit: false, + err: true, + errContains: "hostname is not currently supported on driver group1", + }, } { t.Run(tc.name, func(t *testing.T) { require := require.New(t) diff --git a/client/taskenv/network.go b/client/taskenv/network.go new file mode 100644 index 000000000000..3bbafaa0c111 --- /dev/null +++ b/client/taskenv/network.go @@ -0,0 +1,29 @@ +package taskenv + +import ( + "github.com/hashicorp/nomad/nomad/structs" +) + +// InterpolateNetworks returns an interpolated copy of the task group networks +// with values from the task's environment. +// +// Current interoperable fields: +// - Hostname +func InterpolateNetworks(taskEnv *TaskEnv, networks structs.Networks) structs.Networks { + + // Guard against not having a valid taskEnv. This can be the case if the + // PreKilling or Exited hook is run before Poststart. + if taskEnv == nil || networks == nil { + return nil + } + + // Create a copy of the networks array, so we can manipulate the copy. + interpolated := networks.Copy() + + // Iterate the copy and perform the interpolation. + for i := range interpolated { + interpolated[i].Hostname = taskEnv.ReplaceEnv(interpolated[i].Hostname) + } + + return interpolated +} diff --git a/client/taskenv/network_test.go b/client/taskenv/network_test.go new file mode 100644 index 000000000000..60589b6f1c3d --- /dev/null +++ b/client/taskenv/network_test.go @@ -0,0 +1,45 @@ +package taskenv + +import ( + "testing" + + "github.com/hashicorp/nomad/nomad/structs" + "github.com/stretchr/testify/assert" +) + +func Test_InterpolateNetworks(t *testing.T) { + testCases := []struct { + inputTaskEnv *TaskEnv + inputNetworks structs.Networks + expectedOutputNetworks structs.Networks + name string + }{ + { + inputTaskEnv: testEnv, + inputNetworks: structs.Networks{ + {Hostname: "my-little-pony"}, + }, + expectedOutputNetworks: structs.Networks{ + {Hostname: "my-little-pony"}, + }, + name: "non-interpolated hostname", + }, + { + inputTaskEnv: testEnv, + inputNetworks: structs.Networks{ + {Hostname: "${foo}-cache-${baz}"}, + }, + expectedOutputNetworks: structs.Networks{ + {Hostname: "bar-cache-blah"}, + }, + name: "interpolated hostname", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actualOutput := InterpolateNetworks(tc.inputTaskEnv, tc.inputNetworks) + assert.Equal(t, tc.expectedOutputNetworks, actualOutput, tc.name) + }) + } +} diff --git a/command/agent/job_endpoint.go b/command/agent/job_endpoint.go index 65967985797a..512331e4ab03 100644 --- a/command/agent/job_endpoint.go +++ b/command/agent/job_endpoint.go @@ -1200,10 +1200,11 @@ func ApiNetworkResourceToStructs(in []*api.NetworkResource) []*structs.NetworkRe out = make([]*structs.NetworkResource, len(in)) for i, nw := range in { out[i] = &structs.NetworkResource{ - Mode: nw.Mode, - CIDR: nw.CIDR, - IP: nw.IP, - MBits: nw.Megabits(), + Mode: nw.Mode, + CIDR: nw.CIDR, + IP: nw.IP, + Hostname: nw.Hostname, + MBits: nw.Megabits(), } if nw.DNS != nil { diff --git a/command/agent/job_endpoint_test.go b/command/agent/job_endpoint_test.go index 9834ab20de15..470c488f07c2 100644 --- a/command/agent/job_endpoint_test.go +++ b/command/agent/job_endpoint_test.go @@ -2210,8 +2210,9 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) { MemoryMB: helper.IntToPtr(10), Networks: []*api.NetworkResource{ { - IP: "10.10.11.1", - MBits: helper.IntToPtr(10), + IP: "10.10.11.1", + MBits: helper.IntToPtr(10), + Hostname: "foobar", ReservedPorts: []api.Port{ { Label: "http", @@ -2602,8 +2603,9 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) { MemoryMB: 10, Networks: []*structs.NetworkResource{ { - IP: "10.10.11.1", - MBits: 10, + IP: "10.10.11.1", + MBits: 10, + Hostname: "foobar", ReservedPorts: []structs.Port{ { Label: "http", diff --git a/drivers/docker/network.go b/drivers/docker/network.go index d0900d37e0c2..30a49f6eba52 100644 --- a/drivers/docker/network.go +++ b/drivers/docker/network.go @@ -7,12 +7,21 @@ import ( "github.com/hashicorp/nomad/plugins/drivers" ) -// dockerNetSpecLabelKey is used when creating a parent container for -// shared networking. It is a label whos value identifies the container ID of -// the parent container so tasks can configure their network mode accordingly -const dockerNetSpecLabelKey = "docker_sandbox_container_id" +const ( + // dockerNetSpecLabelKey is the label added when we create a pause + // container to own the network namespace, and the NetworkIsolationSpec we + // get back from CreateNetwork has this label set as the container ID. + // We'll use this to generate a hostname for the task in the event the user + // did not specify a custom one. Please see dockerNetSpecHostnameKey. + dockerNetSpecLabelKey = "docker_sandbox_container_id" + + // dockerNetSpecHostnameKey is the label added when we create a pause + // container and the task group network include a user supplied hostname + // parameter. + dockerNetSpecHostnameKey = "docker_sandbox_hostname" +) -func (d *Driver) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, bool, error) { +func (d *Driver) CreateNetwork(allocID string, createSpec *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error) { // Initialize docker API clients client, _, err := d.dockerClients() if err != nil { @@ -32,19 +41,26 @@ func (d *Driver) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, b return nil, false, err } - config, err := d.createSandboxContainerConfig(allocID) + config, err := d.createSandboxContainerConfig(allocID, createSpec) if err != nil { return nil, false, err } - specFromContainer := func(c *docker.Container) *drivers.NetworkIsolationSpec { - return &drivers.NetworkIsolationSpec{ + specFromContainer := func(c *docker.Container, hostname string) *drivers.NetworkIsolationSpec { + spec := &drivers.NetworkIsolationSpec{ Mode: drivers.NetIsolationModeGroup, Path: c.NetworkSettings.SandboxKey, Labels: map[string]string{ dockerNetSpecLabelKey: c.ID, }, } + + // If the user supplied a hostname, set the label. + if hostname != "" { + spec.Labels[dockerNetSpecHostnameKey] = hostname + } + + return spec } // We want to return a flag that tells us if the container already @@ -55,7 +71,7 @@ func (d *Driver) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, b return nil, false, err } if container != nil && container.State.Running { - return specFromContainer(container), false, nil + return specFromContainer(container, createSpec.Hostname), false, nil } container, err = d.createContainer(client, *config, d.config.InfraImage) @@ -76,7 +92,7 @@ func (d *Driver) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, b return nil, false, err } - return specFromContainer(container), true, nil + return specFromContainer(container, createSpec.Hostname), true, nil } func (d *Driver) DestroyNetwork(allocID string, spec *drivers.NetworkIsolationSpec) error { @@ -92,17 +108,18 @@ func (d *Driver) DestroyNetwork(allocID string, spec *drivers.NetworkIsolationSp } // createSandboxContainerConfig creates a docker container configuration which -// starts a container with an empty network namespace -func (d *Driver) createSandboxContainerConfig(allocID string) (*docker.CreateContainerOptions, error) { +// starts a container with an empty network namespace. +func (d *Driver) createSandboxContainerConfig(allocID string, createSpec *drivers.NetworkCreateRequest) (*docker.CreateContainerOptions, error) { return &docker.CreateContainerOptions{ Name: fmt.Sprintf("nomad_init_%s", allocID), Config: &docker.Config{ - Image: d.config.InfraImage, + Image: d.config.InfraImage, + Hostname: createSpec.Hostname, }, HostConfig: &docker.HostConfig{ - // set the network mode to none which creates a network namespace with - // only a loopback interface + // Set the network mode to none which creates a network namespace + // with only a loopback interface. NetworkMode: "none", }, }, nil diff --git a/drivers/docker/network_test.go b/drivers/docker/network_test.go new file mode 100644 index 000000000000..9fada5bf4527 --- /dev/null +++ b/drivers/docker/network_test.go @@ -0,0 +1,66 @@ +package docker + +import ( + "github.com/hashicorp/nomad/plugins/drivers" + "testing" + + docker "github.com/fsouza/go-dockerclient" + "github.com/stretchr/testify/assert" +) + +func TestDriver_createSandboxContainerConfig(t *testing.T) { + testCases := []struct { + inputAllocID string + inputNetworkCreateRequest *drivers.NetworkCreateRequest + expectedOutputOpts *docker.CreateContainerOptions + name string + }{ + { + inputAllocID: "768b5e8c-a52e-825c-d564-51100230eb62", + inputNetworkCreateRequest: &drivers.NetworkCreateRequest{ + Hostname: "", + }, + expectedOutputOpts: &docker.CreateContainerOptions{ + Name: "nomad_init_768b5e8c-a52e-825c-d564-51100230eb62", + Config: &docker.Config{ + Image: "gcr.io/google_containers/pause-amd64:3.1", + }, + HostConfig: &docker.HostConfig{ + NetworkMode: "none", + }, + }, + name: "no input hostname", + }, + { + inputAllocID: "768b5e8c-a52e-825c-d564-51100230eb62", + inputNetworkCreateRequest: &drivers.NetworkCreateRequest{ + Hostname: "linux", + }, + expectedOutputOpts: &docker.CreateContainerOptions{ + Name: "nomad_init_768b5e8c-a52e-825c-d564-51100230eb62", + Config: &docker.Config{ + Image: "gcr.io/google_containers/pause-amd64:3.1", + Hostname: "linux", + }, + HostConfig: &docker.HostConfig{ + NetworkMode: "none", + }, + }, + name: "supplied input hostname", + }, + } + + d := &Driver{ + config: &DriverConfig{ + InfraImage: "gcr.io/google_containers/pause-amd64:3.1", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actualOutput, err := d.createSandboxContainerConfig(tc.inputAllocID, tc.inputNetworkCreateRequest) + assert.Nil(t, err, tc.name) + assert.Equal(t, tc.expectedOutputOpts, actualOutput, tc.name) + }) + } +} diff --git a/e2e/networking/inputs/docker_bridged_hostname.nomad b/e2e/networking/inputs/docker_bridged_hostname.nomad new file mode 100644 index 000000000000..bac6fa808faa --- /dev/null +++ b/e2e/networking/inputs/docker_bridged_hostname.nomad @@ -0,0 +1,24 @@ +job "networking" { + datacenters = ["dc1", "dc2"] + + constraint { + attribute = "${attr.kernel.name}" + value = "linux" + } + + group "bridged" { + network { + hostname = "mylittlepony" + mode = "bridge" + } + + task "sleep" { + driver = "docker" + config { + image = "busybox:1" + command = "/bin/sleep" + args = ["300"] + } + } + } +} diff --git a/e2e/networking/inputs/docker_bridged_hostname_interpolation.nomad b/e2e/networking/inputs/docker_bridged_hostname_interpolation.nomad new file mode 100644 index 000000000000..2d09ed6ec9a1 --- /dev/null +++ b/e2e/networking/inputs/docker_bridged_hostname_interpolation.nomad @@ -0,0 +1,24 @@ +job "networking" { + datacenters = ["dc1", "dc2"] + + constraint { + attribute = "${attr.kernel.name}" + value = "linux" + } + + group "bridged" { + network { + hostname = "mylittlepony-${NOMAD_ALLOC_INDEX}" + mode = "bridge" + } + + task "sleep" { + driver = "docker" + config { + image = "busybox:1" + command = "/bin/sleep" + args = ["300"] + } + } + } +} diff --git a/e2e/networking/networking.go b/e2e/networking/networking.go index 705a3965b47c..90c86e66a7b0 100644 --- a/e2e/networking/networking.go +++ b/e2e/networking/networking.go @@ -1,14 +1,94 @@ package networking import ( + "os" + "strings" + "github.com/hashicorp/nomad/e2e/e2eutil" "github.com/hashicorp/nomad/e2e/framework" + "github.com/hashicorp/nomad/helper/uuid" ) +type NetworkingE2ETest struct { + framework.TC + jobIDs []string +} + func init() { framework.AddSuites(&framework.TestSuite{ Component: "Networking", CanRunLocal: true, - Cases: []framework.TestCase{e2eutil.NewE2EJob("networking/inputs/basic.nomad")}, + Cases: []framework.TestCase{ + e2eutil.NewE2EJob("networking/inputs/basic.nomad"), + new(NetworkingE2ETest), + }, }) } + +func (tc *NetworkingE2ETest) BeforeAll(f *framework.F) { + e2eutil.WaitForLeader(f.T(), tc.Nomad()) + e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1) +} + +func (tc *NetworkingE2ETest) AfterEach(f *framework.F) { + if os.Getenv("NOMAD_TEST_SKIPCLEANUP") == "1" { + return + } + + for _, jobID := range tc.jobIDs { + _, err := e2eutil.Command("nomad", "job", "stop", "-purge", jobID) + f.NoError(err) + } + tc.jobIDs = []string{} + + _, err := e2eutil.Command("nomad", "system", "gc") + f.NoError(err) +} + +func (tc *NetworkingE2ETest) TestNetworking_DockerBridgedHostname(f *framework.F) { + + jobID := "test-networking-" + uuid.Generate()[0:8] + f.NoError(e2eutil.Register(jobID, "networking/inputs/docker_bridged_hostname.nomad")) + tc.jobIDs = append(tc.jobIDs, jobID) + f.NoError(e2eutil.WaitForAllocStatusExpected(jobID, "default", []string{"running"}), + "job should be running with 1 alloc") + + // Grab the allocations for the job. + allocs, _, err := tc.Nomad().Jobs().Allocations(jobID, false, nil) + f.NoError(err, "failed to get allocs for job") + f.Len(allocs, 1, "job should have one alloc") + + // Run the hostname command within the allocation. + hostnameOutput, err := e2eutil.AllocExec(allocs[0].ID, "sleep", "hostname", "default", nil) + f.NoError(err, "failed to run hostname exec command") + f.Equal("mylittlepony", strings.TrimSpace(hostnameOutput), "incorrect hostname set within container") + + // Check the /etc/hosts file for the correct IP address and hostname entry. + hostsOutput, err := e2eutil.AllocExec(allocs[0].ID, "sleep", "cat /etc/hosts", "default", nil) + f.NoError(err, "failed to run hostname exec command") + f.Contains(hostsOutput, "mylittlepony", "/etc/hosts doesn't contain hostname entry") +} + +func (tc *NetworkingE2ETest) TestNetworking_DockerBridgedHostnameInterpolation(f *framework.F) { + + jobID := "test-networking-" + uuid.Generate()[0:8] + f.NoError(e2eutil.Register(jobID, "networking/inputs/docker_bridged_hostname_interpolation.nomad")) + tc.jobIDs = append(tc.jobIDs, jobID) + f.NoError(e2eutil.WaitForAllocStatusExpected(jobID, "default", []string{"running"}), + "job should be running with 1 alloc") + + // Grab the allocations for the job. + allocs, _, err := tc.Nomad().Jobs().Allocations(jobID, false, nil) + f.NoError(err, "failed to get allocs for job") + f.Len(allocs, 1, "job should have one alloc") + + // Run the hostname command within the allocation. + hostnameOutput, err := e2eutil.AllocExec(allocs[0].ID, "sleep", "hostname", "default", nil) + f.NoError(err, "failed to run hostname exec command") + f.Equal("mylittlepony-0", strings.TrimSpace(hostnameOutput), "incorrect hostname set within container") + + // Check the /etc/hosts file for the correct IP address and hostname entry. + hostsOutput, err := e2eutil.AllocExec(allocs[0].ID, "sleep", "cat /etc/hosts", "default", nil) + f.NoError(err, "failed to run hostname exec command") + f.Contains(hostsOutput, "mylittlepony-0", "/etc/hosts doesn't contain hostname entry") +} diff --git a/go.mod b/go.mod index 8310f70b9e87..90615692656e 100644 --- a/go.mod +++ b/go.mod @@ -93,6 +93,7 @@ require ( github.com/kr/pty v1.1.5 github.com/kr/text v0.2.0 github.com/mattn/go-colorable v0.1.7 + github.com/miekg/dns v1.1.26 github.com/mitchellh/cli v1.1.0 github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286 github.com/mitchellh/copystructure v1.1.1 diff --git a/jobspec/parse_network.go b/jobspec/parse_network.go index 6b7e9474e8d8..795f38a3eb99 100644 --- a/jobspec/parse_network.go +++ b/jobspec/parse_network.go @@ -23,6 +23,7 @@ func ParseNetwork(o *ast.ObjectList) (*api.NetworkResource, error) { "mbits", "dns", "port", + "hostname", } if err := checkHCLKeys(o.Items[0].Val, valid); err != nil { return nil, multierror.Prefix(err, "network ->") diff --git a/jobspec/test-fixtures/tg-network-with-hostname.hcl b/jobspec/test-fixtures/tg-network-with-hostname.hcl new file mode 100644 index 000000000000..0f84ab0163a6 --- /dev/null +++ b/jobspec/test-fixtures/tg-network-with-hostname.hcl @@ -0,0 +1,34 @@ +job "foo" { + datacenters = ["dc1"] + + group "bar" { + count = 3 + shutdown_delay = "14s" + + network { + mode = "bridge" + hostname = "foobar" + + port "http" { + static = 80 + to = 8080 + host_network = "public" + } + } + + task "bar" { + driver = "raw_exec" + + config { + command = "bash" + args = ["-c", "echo hi"] + } + + resources { + network { + mbits = 10 + } + } + } + } +} diff --git a/nomad/plan_normalization_test.go b/nomad/plan_normalization_test.go index 1082c44e50f9..ba427d423754 100644 --- a/nomad/plan_normalization_test.go +++ b/nomad/plan_normalization_test.go @@ -62,5 +62,5 @@ func TestPlanNormalize(t *testing.T) { } optimizedLogSize := buf.Len() - assert.Less(t, float64(optimizedLogSize)/float64(unoptimizedLogSize), 0.66) + assert.Less(t, float64(optimizedLogSize)/float64(unoptimizedLogSize), 0.67) } diff --git a/nomad/structs/diff_test.go b/nomad/structs/diff_test.go index 6eabcdc8b004..76221d5a208c 100644 --- a/nomad/structs/diff_test.go +++ b/nomad/structs/diff_test.go @@ -3422,10 +3422,11 @@ func TestTaskGroupDiff(t *testing.T) { Old: &TaskGroup{ Networks: Networks{ { - Device: "foo", - CIDR: "foo", - IP: "foo", - MBits: 100, + Device: "foo", + CIDR: "foo", + IP: "foo", + MBits: 100, + Hostname: "foo", ReservedPorts: []Port{ { Label: "foo", @@ -3438,10 +3439,11 @@ func TestTaskGroupDiff(t *testing.T) { New: &TaskGroup{ Networks: Networks{ { - Device: "bar", - CIDR: "bar", - IP: "bar", - MBits: 200, + Device: "bar", + CIDR: "bar", + IP: "bar", + MBits: 200, + Hostname: "bar", DynamicPorts: []Port{ { Label: "bar", @@ -3462,6 +3464,12 @@ func TestTaskGroupDiff(t *testing.T) { Type: DiffTypeAdded, Name: "Network", Fields: []*FieldDiff{ + { + Type: DiffTypeAdded, + Name: "Hostname", + Old: "", + New: "bar", + }, { Type: DiffTypeAdded, Name: "MBits", @@ -3518,6 +3526,12 @@ func TestTaskGroupDiff(t *testing.T) { Type: DiffTypeDeleted, Name: "Network", Fields: []*FieldDiff{ + { + Type: DiffTypeDeleted, + Name: "Hostname", + Old: "foo", + New: "", + }, { Type: DiffTypeDeleted, Name: "MBits", diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 04701c5e53ed..f190f96ca810 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -25,15 +25,10 @@ import ( "strings" "time" - "github.com/hashicorp/nomad/lib/cpuset" - "github.com/hashicorp/cronexpr" "github.com/hashicorp/go-msgpack/codec" "github.com/hashicorp/go-multierror" "github.com/hashicorp/go-version" - "github.com/mitchellh/copystructure" - "golang.org/x/crypto/blake2b" - "github.com/hashicorp/nomad/acl" "github.com/hashicorp/nomad/command/agent/host" "github.com/hashicorp/nomad/command/agent/pprof" @@ -41,8 +36,12 @@ import ( "github.com/hashicorp/nomad/helper/args" "github.com/hashicorp/nomad/helper/constraints/semver" "github.com/hashicorp/nomad/helper/uuid" + "github.com/hashicorp/nomad/lib/cpuset" "github.com/hashicorp/nomad/lib/kheap" psstructs "github.com/hashicorp/nomad/plugins/shared/structs" + "github.com/miekg/dns" + "github.com/mitchellh/copystructure" + "golang.org/x/crypto/blake2b" ) var ( @@ -2532,6 +2531,7 @@ type NetworkResource struct { Device string // Name of the device CIDR string // CIDR block of addresses IP string // Host IP address + Hostname string `json:",omitempty"` // Hostname of the network namespace MBits int // Throughput DNS *DNSConfig // DNS Configuration ReservedPorts []Port // Host Reserved ports @@ -2540,7 +2540,7 @@ type NetworkResource struct { func (nr *NetworkResource) Hash() uint32 { var data []byte - data = append(data, []byte(fmt.Sprintf("%s%s%s%s%d", nr.Mode, nr.Device, nr.CIDR, nr.IP, nr.MBits))...) + data = append(data, []byte(fmt.Sprintf("%s%s%s%s%s%d", nr.Mode, nr.Device, nr.CIDR, nr.IP, nr.Hostname, nr.MBits))...) for i, port := range nr.ReservedPorts { data = append(data, []byte(fmt.Sprintf("r%d%s%d%d", i, port.Label, port.Value, port.To))...) @@ -6304,7 +6304,18 @@ func (tg *TaskGroup) validateNetworks() error { mErr.Errors = append(mErr.Errors, err) } } + + // Validate the hostname field to be a valid DNS name. If the parameter + // looks like it includes an interpolation value, we skip this. It + // would be nice to validate additional parameters, but this isn't the + // right place. + if net.Hostname != "" && !strings.Contains(net.Hostname, "${") { + if _, ok := dns.IsDomainName(net.Hostname); !ok { + mErr.Errors = append(mErr.Errors, errors.New("Hostname is not a valid DNS name")) + } + } } + // Check for duplicate tasks or port labels, and no duplicated static ports for _, task := range tg.Tasks { if task.Resources == nil { diff --git a/nomad/structs/structs_test.go b/nomad/structs/structs_test.go index 2409f7021fb9..ab14ba01a160 100644 --- a/nomad/structs/structs_test.go +++ b/nomad/structs/structs_test.go @@ -1442,6 +1442,33 @@ func TestTaskGroupNetwork_Validate(t *testing.T) { }, }, }, + { + TG: &TaskGroup{ + Tasks: []*Task{ + {Driver: "docker"}, + }, + Networks: []*NetworkResource{ + { + Mode: "bridge", + Hostname: "foobar", + }, + }, + }, + }, + { + TG: &TaskGroup{ + Tasks: []*Task{ + {Name: "hostname-invalid-dns-name"}, + }, + Networks: []*NetworkResource{ + { + Mode: "bridge", + Hostname: "............", + }, + }, + }, + ErrContains: "Hostname is not a valid DNS name", + }, } for i := range cases { @@ -1599,6 +1626,56 @@ func TestTask_Validate_Resources(t *testing.T) { } } +func TestNetworkResource_Copy(t *testing.T) { + testCases := []struct { + inputNetworkResource *NetworkResource + name string + }{ + { + inputNetworkResource: nil, + name: "nil input check", + }, + { + inputNetworkResource: &NetworkResource{ + Mode: "bridge", + Device: "eth0", + CIDR: "10.0.0.1/8", + IP: "10.1.1.13", + Hostname: "foobar", + MBits: 1000, + DNS: &DNSConfig{ + Servers: []string{"8.8.8.8", "8.8.4.4"}, + Searches: []string{"example.com"}, + Options: []string{"ndot:2"}, + }, + ReservedPorts: []Port{ + { + Label: "foo", + Value: 1313, + To: 1313, + HostNetwork: "private", + }, + }, + DynamicPorts: []Port{ + { + Label: "bar", + To: 1414, + HostNetwork: "public", + }, + }, + }, + name: "fully populated input check", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + output := tc.inputNetworkResource.Copy() + assert.Equal(t, tc.inputNetworkResource, output, tc.name) + }) + } +} + func TestTask_Validate_Services(t *testing.T) { s1 := &Service{ Name: "service-name", @@ -2559,13 +2636,11 @@ func TestConstraint_Validate(t *testing.T) { } func TestAffinity_Validate(t *testing.T) { - type tc struct { affinity *Affinity err error name string } - testCases := []tc{ { affinity: &Affinity{}, @@ -3484,7 +3559,6 @@ func TestReschedulePolicy_Validate(t *testing.T) { ReschedulePolicy *ReschedulePolicy errors []error } - testCases := []testCase{ { desc: "Nil", @@ -4061,7 +4135,6 @@ func TestAllocation_Terminated(t *testing.T) { DesiredStatus string Terminated bool } - harness := []desiredState{ { ClientStatus: AllocClientStatusPending, @@ -4105,7 +4178,6 @@ func TestAllocation_ShouldReschedule(t *testing.T) { RescheduleTrackers []*RescheduleEvent ShouldReschedule bool } - fail := time.Now() harness := []testCase{ @@ -4238,7 +4310,6 @@ func TestAllocation_LastEventTime(t *testing.T) { taskState map[string]*TaskState expectedLastEventTime time.Time } - t1 := time.Now().UTC() testCases := []testCase{ @@ -4903,7 +4974,6 @@ func TestRescheduleTracker_Copy(t *testing.T) { original *RescheduleTracker expected *RescheduleTracker } - cases := []testCase{ {nil, nil}, {&RescheduleTracker{Events: []*RescheduleEvent{ @@ -5074,7 +5144,6 @@ func TestScalingPolicy_Validate(t *testing.T) { input *ScalingPolicy expectedErr string } - cases := []testCase{ { name: "full horizontal policy", @@ -5706,7 +5775,6 @@ func TestSpread_Validate(t *testing.T) { err error name string } - testCases := []tc{ { spread: &Spread{}, diff --git a/plugins/drivers/driver.go b/plugins/drivers/driver.go index c84d42166252..f47dc5a2815b 100644 --- a/plugins/drivers/driver.go +++ b/plugins/drivers/driver.go @@ -90,7 +90,7 @@ type ExecOptions struct { // network namespace for which tasks can join. This only needs to be implemented // if the driver MUST create the network namespace type DriverNetworkManager interface { - CreateNetwork(allocID string) (*NetworkIsolationSpec, bool, error) + CreateNetwork(allocID string, request *NetworkCreateRequest) (*NetworkIsolationSpec, bool, error) DestroyNetwork(allocID string, spec *NetworkIsolationSpec) error } @@ -211,6 +211,15 @@ type HostsConfig struct { Address string } +// NetworkCreateRequest contains all the relevant information when creating a +// network via DriverNetworkManager.CreateNetwork. +type NetworkCreateRequest struct { + + // Hostname is the hostname the user has specified that the network should + // be configured with. + Hostname string +} + // MountConfigSupport is an enum that defaults to "all" for backwards // compatibility with community drivers. type MountConfigSupport int32 diff --git a/plugins/drivers/proto/driver.pb.go b/plugins/drivers/proto/driver.pb.go index b682661b373a..66407ef55f2b 100644 --- a/plugins/drivers/proto/driver.pb.go +++ b/plugins/drivers/proto/driver.pb.go @@ -1657,7 +1657,9 @@ func (m *ExecTaskStreamingResponse) GetResult() *ExitResult { type CreateNetworkRequest struct { // AllocID of the allocation the network is associated with - AllocId string `protobuf:"bytes,1,opt,name=alloc_id,json=allocId,proto3" json:"alloc_id,omitempty"` + AllocId string `protobuf:"bytes,1,opt,name=alloc_id,json=allocId,proto3" json:"alloc_id,omitempty"` + // Hostname of the network namespace + Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1695,6 +1697,13 @@ func (m *CreateNetworkRequest) GetAllocId() string { return "" } +func (m *CreateNetworkRequest) GetHostname() string { + if m != nil { + return m.Hostname + } + return "" +} + type CreateNetworkResponse struct { IsolationSpec *NetworkIsolationSpec `protobuf:"bytes,1,opt,name=isolation_spec,json=isolationSpec,proto3" json:"isolation_spec,omitempty"` // created indicates that the network namespace is newly created @@ -3673,25 +3682,25 @@ func init() { } var fileDescriptor_4a8f45747846a74d = []byte{ - // 3771 bytes of a gzipped FileDescriptorProto + // 3776 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x5a, 0xcd, 0x6f, 0x1b, 0x49, - 0x76, 0x57, 0xb3, 0xf9, 0xf9, 0x48, 0x51, 0xad, 0xb2, 0x6c, 0xd3, 0xdc, 0x24, 0xe3, 0xed, 0x60, - 0x02, 0x61, 0x77, 0x86, 0x9e, 0xd1, 0x22, 0xe3, 0xf1, 0xac, 0x67, 0x3d, 0x1c, 0x8a, 0xb6, 0x34, + 0x76, 0x57, 0xb3, 0xf9, 0xf9, 0x48, 0x51, 0xad, 0xb2, 0x6c, 0xd3, 0x9c, 0x24, 0xe3, 0xed, 0x60, + 0x02, 0x61, 0x77, 0x86, 0x9e, 0xd5, 0x22, 0xe3, 0xf1, 0xac, 0x67, 0x3d, 0x1c, 0x8a, 0xb6, 0x34, 0x96, 0x28, 0xa5, 0x48, 0xc1, 0xeb, 0x38, 0x3b, 0x9d, 0x16, 0xbb, 0x4c, 0xb5, 0xc5, 0xfe, 0x98, 0xae, 0xa6, 0x2c, 0x6d, 0x10, 0x24, 0xd8, 0x00, 0xc1, 0x06, 0x48, 0x90, 0x5c, 0x26, 0x7b, 0xc9, 0x69, 0x81, 0x9c, 0xf2, 0x0f, 0x04, 0x1b, 0xec, 0x29, 0x87, 0xfc, 0x13, 0xb9, 0xe4, 0x96, 0x63, 0x72, 0xca, 0x35, 0xa8, 0x8f, 0x6e, 0x76, 0x93, 0xf4, 0xb8, 0x49, 0xf9, 0xc4, 0x7e, 0xf5, 0xf1, 0xab, 0xc7, 0xf7, 0x5e, 0xbd, 0x7a, 0xf5, 0xea, 0x81, 0xee, 0x8f, 0x27, 0x23, 0xdb, 0xa5, 0xf7, - 0xac, 0xc0, 0xbe, 0x20, 0x01, 0xbd, 0xe7, 0x07, 0x5e, 0xe8, 0x49, 0xaa, 0xc5, 0x09, 0xf4, 0xfe, + 0xac, 0xc0, 0xbe, 0x20, 0x01, 0xbd, 0xe7, 0x07, 0x5e, 0xe8, 0x49, 0xaa, 0xc5, 0x09, 0xf4, 0xc1, 0x99, 0x49, 0xcf, 0xec, 0xa1, 0x17, 0xf8, 0x2d, 0xd7, 0x73, 0x4c, 0xab, 0x25, 0xe7, 0xb4, 0xe4, 0x1c, 0x31, 0xac, 0xf9, 0x7b, 0x23, 0xcf, 0x1b, 0x8d, 0x89, 0x40, 0x38, 0x9d, 0xbc, 0xbc, 0x67, - 0x4d, 0x02, 0x33, 0xb4, 0x3d, 0x57, 0xf6, 0xbf, 0x37, 0xdb, 0x1f, 0xda, 0x0e, 0xa1, 0xa1, 0xe9, - 0xf8, 0x72, 0xc0, 0xfb, 0x11, 0x2f, 0xf4, 0xcc, 0x0c, 0x88, 0x75, 0xef, 0x6c, 0x38, 0xa6, 0x3e, - 0x19, 0xb2, 0x5f, 0x83, 0x7d, 0xc8, 0x61, 0x1f, 0xcc, 0x0c, 0xa3, 0x61, 0x30, 0x19, 0x86, 0x11, + 0x4d, 0x02, 0x33, 0xb4, 0x3d, 0x57, 0xf6, 0xbf, 0x3f, 0xdb, 0x1f, 0xda, 0x0e, 0xa1, 0xa1, 0xe9, + 0xf8, 0x72, 0xc0, 0x07, 0x11, 0x2f, 0xf4, 0xcc, 0x0c, 0x88, 0x75, 0xef, 0x6c, 0x38, 0xa6, 0x3e, + 0x19, 0xb2, 0x5f, 0x83, 0x7d, 0xc8, 0x61, 0x1f, 0xce, 0x0c, 0xa3, 0x61, 0x30, 0x19, 0x86, 0x11, 0xe7, 0x66, 0x18, 0x06, 0xf6, 0xe9, 0x24, 0x24, 0x62, 0xb4, 0x7e, 0x07, 0x6e, 0x0f, 0x4c, 0x7a, 0xde, 0xf1, 0xdc, 0x97, 0xf6, 0xa8, 0x3f, 0x3c, 0x23, 0x8e, 0x89, 0xc9, 0x37, 0x13, 0x42, 0x43, 0xfd, 0x4f, 0xa0, 0x31, 0xdf, 0x45, 0x7d, 0xcf, 0xa5, 0x04, 0x7d, 0x01, 0x79, 0xb6, 0x64, 0x43, - 0xb9, 0xab, 0x6c, 0x57, 0x77, 0x3e, 0x68, 0xbd, 0x49, 0x04, 0x82, 0x87, 0x96, 0x64, 0xb5, 0xd5, + 0xb9, 0xab, 0x6c, 0x57, 0x77, 0x3e, 0x6c, 0xbd, 0x49, 0x04, 0x82, 0x87, 0x96, 0x64, 0xb5, 0xd5, 0xf7, 0xc9, 0x10, 0xf3, 0x99, 0xfa, 0x4d, 0xb8, 0xd1, 0x31, 0x7d, 0xf3, 0xd4, 0x1e, 0xdb, 0xa1, 0x4d, 0x68, 0xb4, 0xe8, 0x04, 0xb6, 0xd2, 0xcd, 0x72, 0xc1, 0x9f, 0x41, 0x6d, 0x98, 0x68, 0x97, 0x0b, 0x3f, 0x68, 0x65, 0x92, 0x7d, 0x6b, 0x97, 0x53, 0x29, 0xe0, 0x14, 0x9c, 0xbe, 0x05, 0xe8, @@ -3699,217 +3708,217 @@ var fileDescriptor_4a8f45747846a74d = []byte{ 0xc9, 0xcc, 0x2b, 0x80, 0x58, 0x8e, 0x8c, 0x15, 0x75, 0xbb, 0xba, 0xf3, 0x55, 0x46, 0x56, 0x16, 0xe0, 0xb5, 0xda, 0x31, 0x58, 0xd7, 0x0d, 0x83, 0x2b, 0x9c, 0x40, 0x47, 0x5f, 0x43, 0xf1, 0x8c, 0x98, 0xe3, 0xf0, 0xac, 0x91, 0xbb, 0xab, 0x6c, 0xd7, 0x77, 0x1e, 0x5f, 0x63, 0x9d, 0x3d, 0x0e, - 0xd4, 0x0f, 0xcd, 0x90, 0x60, 0x89, 0x8a, 0x3e, 0x04, 0x24, 0xbe, 0x0c, 0x8b, 0xd0, 0x61, 0x60, + 0xd4, 0x0f, 0xcd, 0x90, 0x60, 0x89, 0x8a, 0x3e, 0x02, 0x24, 0xbe, 0x0c, 0x8b, 0xd0, 0x61, 0x60, 0xfb, 0xcc, 0x24, 0x1b, 0xea, 0x5d, 0x65, 0xbb, 0x82, 0x37, 0x45, 0xcf, 0xee, 0xb4, 0xa3, 0xe9, 0xc3, 0xc6, 0x0c, 0xb7, 0x48, 0x03, 0xf5, 0x9c, 0x5c, 0x71, 0x8d, 0x54, 0x30, 0xfb, 0x44, 0x4f, - 0xa0, 0x70, 0x61, 0x8e, 0x27, 0x84, 0xb3, 0x5c, 0xdd, 0xf9, 0xf8, 0x6d, 0xe6, 0x21, 0x4d, 0x74, - 0x2a, 0x07, 0x2c, 0xe6, 0x7f, 0x96, 0xfb, 0x54, 0xd1, 0x1f, 0x40, 0x35, 0xc1, 0x37, 0xaa, 0x03, - 0x9c, 0xf4, 0x76, 0xbb, 0x83, 0x6e, 0x67, 0xd0, 0xdd, 0xd5, 0xd6, 0xd0, 0x3a, 0x54, 0x4e, 0x7a, - 0x7b, 0xdd, 0xf6, 0xc1, 0x60, 0xef, 0xb9, 0xa6, 0xa0, 0x2a, 0x94, 0x22, 0x22, 0xa7, 0x5f, 0x02, - 0xc2, 0x64, 0xe8, 0x5d, 0x90, 0x80, 0x19, 0xb2, 0xd4, 0x2a, 0xba, 0x0d, 0xa5, 0xd0, 0xa4, 0xe7, - 0x86, 0x6d, 0x49, 0x9e, 0x8b, 0x8c, 0xdc, 0xb7, 0xd0, 0x3e, 0x14, 0xcf, 0x4c, 0xd7, 0x1a, 0xbf, - 0x9d, 0xef, 0xb4, 0xa8, 0x19, 0xf8, 0x1e, 0x9f, 0x88, 0x25, 0x00, 0xb3, 0xee, 0xd4, 0xca, 0x42, - 0x01, 0xfa, 0x73, 0xd0, 0xfa, 0xa1, 0x19, 0x84, 0x49, 0x76, 0xba, 0x90, 0x67, 0xeb, 0x4b, 0x8b, - 0x5e, 0x66, 0x4d, 0xb1, 0x33, 0x31, 0x9f, 0xae, 0xff, 0x6f, 0x0e, 0x36, 0x13, 0xd8, 0xd2, 0x52, - 0x9f, 0x41, 0x31, 0x20, 0x74, 0x32, 0x0e, 0x39, 0x7c, 0x7d, 0xe7, 0x51, 0x46, 0xf8, 0x39, 0xa4, - 0x16, 0xe6, 0x30, 0x58, 0xc2, 0xa1, 0x6d, 0xd0, 0xc4, 0x0c, 0x83, 0x04, 0x81, 0x17, 0x18, 0x0e, - 0x1d, 0x71, 0xa9, 0x55, 0x70, 0x5d, 0xb4, 0x77, 0x59, 0xf3, 0x21, 0x1d, 0x25, 0xa4, 0xaa, 0x5e, - 0x53, 0xaa, 0xc8, 0x04, 0xcd, 0x25, 0xe1, 0x6b, 0x2f, 0x38, 0x37, 0x98, 0x68, 0x03, 0xdb, 0x22, - 0x8d, 0x3c, 0x07, 0xfd, 0x24, 0x23, 0x68, 0x4f, 0x4c, 0x3f, 0x92, 0xb3, 0xf1, 0x86, 0x9b, 0x6e, - 0xd0, 0x7f, 0x08, 0x45, 0xf1, 0x4f, 0x99, 0x25, 0xf5, 0x4f, 0x3a, 0x9d, 0x6e, 0xbf, 0xaf, 0xad, - 0xa1, 0x0a, 0x14, 0x70, 0x77, 0x80, 0x99, 0x85, 0x55, 0xa0, 0xf0, 0xb8, 0x3d, 0x68, 0x1f, 0x68, - 0x39, 0xfd, 0x07, 0xb0, 0xf1, 0xcc, 0xb4, 0xc3, 0x2c, 0xc6, 0xa5, 0x7b, 0xa0, 0x4d, 0xc7, 0x4a, - 0xed, 0xec, 0xa7, 0xb4, 0x93, 0x5d, 0x34, 0xdd, 0x4b, 0x3b, 0x9c, 0xd1, 0x87, 0x06, 0x2a, 0x09, - 0x02, 0xa9, 0x02, 0xf6, 0xa9, 0xbf, 0x86, 0x8d, 0x7e, 0xe8, 0xf9, 0x99, 0x2c, 0xff, 0x47, 0x50, - 0x62, 0xa7, 0x8d, 0x37, 0x09, 0xa5, 0xe9, 0xdf, 0x69, 0x89, 0xd3, 0xa8, 0x15, 0x9d, 0x46, 0xad, - 0x5d, 0x79, 0x5a, 0xe1, 0x68, 0x24, 0xba, 0x05, 0x45, 0x6a, 0x8f, 0x5c, 0x73, 0x2c, 0xbd, 0x85, - 0xa4, 0x74, 0xc4, 0x8c, 0x3c, 0x5a, 0x58, 0x1a, 0x7e, 0x07, 0xd0, 0x2e, 0xa1, 0x61, 0xe0, 0x5d, - 0x65, 0xe2, 0x67, 0x0b, 0x0a, 0x2f, 0xbd, 0x60, 0x28, 0x36, 0x62, 0x19, 0x0b, 0x82, 0x6d, 0xaa, - 0x14, 0x88, 0xc4, 0xfe, 0x10, 0xd0, 0xbe, 0xcb, 0xce, 0x94, 0x6c, 0x8a, 0xf8, 0x87, 0x1c, 0xdc, - 0x48, 0x8d, 0x97, 0xca, 0x58, 0x7d, 0x1f, 0x32, 0xc7, 0x34, 0xa1, 0x62, 0x1f, 0xa2, 0x23, 0x28, - 0x8a, 0x11, 0x52, 0x92, 0xf7, 0x97, 0x00, 0x12, 0xc7, 0x94, 0x84, 0x93, 0x30, 0x0b, 0x8d, 0x5e, - 0x7d, 0xb7, 0x46, 0xff, 0x1a, 0xb4, 0xe8, 0x7f, 0xd0, 0xb7, 0xea, 0xe6, 0x2b, 0xb8, 0x31, 0xf4, - 0xc6, 0x63, 0x32, 0x64, 0xd6, 0x60, 0xd8, 0x6e, 0x48, 0x82, 0x0b, 0x73, 0xfc, 0x76, 0xbb, 0x41, - 0xd3, 0x59, 0xfb, 0x72, 0x92, 0xfe, 0x02, 0x36, 0x13, 0x0b, 0x4b, 0x45, 0x3c, 0x86, 0x02, 0x65, - 0x0d, 0x52, 0x13, 0x1f, 0x2d, 0xa9, 0x09, 0x8a, 0xc5, 0x74, 0xfd, 0x86, 0x00, 0xef, 0x5e, 0x10, - 0x37, 0xfe, 0x5b, 0xfa, 0x2e, 0x6c, 0xf6, 0xb9, 0x99, 0x66, 0xb2, 0xc3, 0xa9, 0x89, 0xe7, 0x52, - 0x26, 0xbe, 0x05, 0x28, 0x89, 0x22, 0x0d, 0xf1, 0x0a, 0x36, 0xba, 0x97, 0x64, 0x98, 0x09, 0xb9, - 0x01, 0xa5, 0xa1, 0xe7, 0x38, 0xa6, 0x6b, 0x35, 0x72, 0x77, 0xd5, 0xed, 0x0a, 0x8e, 0xc8, 0xe4, - 0x5e, 0x54, 0xb3, 0xee, 0x45, 0xfd, 0xef, 0x14, 0xd0, 0xa6, 0x6b, 0x4b, 0x41, 0x32, 0xee, 0x43, - 0x8b, 0x01, 0xb1, 0xb5, 0x6b, 0x58, 0x52, 0xb2, 0x3d, 0x72, 0x17, 0xa2, 0x9d, 0x04, 0x41, 0xc2, - 0x1d, 0xa9, 0xd7, 0x74, 0x47, 0xfa, 0x1e, 0xfc, 0x4e, 0xc4, 0x4e, 0x3f, 0x0c, 0x88, 0xe9, 0xd8, - 0xee, 0x68, 0xff, 0xe8, 0xc8, 0x27, 0x82, 0x71, 0x84, 0x20, 0x6f, 0x99, 0xa1, 0x29, 0x19, 0xe3, - 0xdf, 0x6c, 0xd3, 0x0f, 0xc7, 0x1e, 0x8d, 0x37, 0x3d, 0x27, 0xf4, 0xff, 0x50, 0xa1, 0x31, 0x07, - 0x15, 0x89, 0xf7, 0x05, 0x14, 0x28, 0x09, 0x27, 0xbe, 0x34, 0x95, 0x6e, 0x66, 0x86, 0x17, 0xe3, - 0xb5, 0xfa, 0x0c, 0x0c, 0x0b, 0x4c, 0x34, 0x82, 0x72, 0x18, 0x5e, 0x19, 0xd4, 0xfe, 0x79, 0x14, - 0x10, 0x1c, 0x5c, 0x17, 0x7f, 0x40, 0x02, 0xc7, 0x76, 0xcd, 0x71, 0xdf, 0xfe, 0x39, 0xc1, 0xa5, - 0x30, 0xbc, 0x62, 0x1f, 0xe8, 0x39, 0x33, 0x78, 0xcb, 0x76, 0xa5, 0xd8, 0x3b, 0xab, 0xae, 0x92, - 0x10, 0x30, 0x16, 0x88, 0xcd, 0x03, 0x28, 0xf0, 0xff, 0xb4, 0x8a, 0x21, 0x6a, 0xa0, 0x86, 0xe1, - 0x15, 0x67, 0xaa, 0x8c, 0xd9, 0x67, 0xf3, 0x21, 0xd4, 0x92, 0xff, 0x80, 0x19, 0xd2, 0x19, 0xb1, - 0x47, 0x67, 0xc2, 0xc0, 0x0a, 0x58, 0x52, 0x4c, 0x93, 0xaf, 0x6d, 0x4b, 0x86, 0xac, 0x05, 0x2c, - 0x08, 0xfd, 0x5f, 0x73, 0x70, 0x67, 0x81, 0x64, 0xa4, 0xb1, 0xbe, 0x48, 0x19, 0xeb, 0x3b, 0x92, - 0x42, 0x64, 0xf1, 0x2f, 0x52, 0x16, 0xff, 0x0e, 0xc1, 0xd9, 0xb6, 0xb9, 0x05, 0x45, 0x72, 0x69, - 0x87, 0xc4, 0x92, 0xa2, 0x92, 0x54, 0x62, 0x3b, 0xe5, 0xaf, 0xbb, 0x9d, 0x3e, 0x86, 0xad, 0x4e, - 0x40, 0xcc, 0x90, 0x48, 0x57, 0x1e, 0xd9, 0xff, 0x1d, 0x28, 0x9b, 0xe3, 0xb1, 0x37, 0x9c, 0xaa, - 0xb5, 0xc4, 0xe9, 0x7d, 0x4b, 0xff, 0x56, 0x81, 0x9b, 0x33, 0x73, 0xa4, 0xa4, 0x4f, 0xa1, 0x6e, - 0x53, 0x6f, 0xcc, 0xff, 0x84, 0x91, 0xb8, 0xc5, 0xfd, 0x78, 0xb9, 0xe3, 0x64, 0x3f, 0xc2, 0xe0, - 0x97, 0xba, 0x75, 0x3b, 0x49, 0x72, 0xab, 0xe2, 0x8b, 0x5b, 0x72, 0x37, 0x47, 0xa4, 0xfe, 0x8f, - 0x0a, 0xdc, 0x94, 0xa7, 0x78, 0xe6, 0x3f, 0xb3, 0x80, 0xe5, 0xdc, 0xbb, 0x66, 0x59, 0x6f, 0xc0, - 0xad, 0x59, 0xbe, 0xa4, 0x5f, 0xff, 0xbf, 0x3c, 0xa0, 0xf9, 0x1b, 0x24, 0xfa, 0x3e, 0xd4, 0x28, - 0x71, 0x2d, 0x43, 0x9c, 0x09, 0xe2, 0xb8, 0x2a, 0xe3, 0x2a, 0x6b, 0x13, 0x87, 0x03, 0x65, 0x6e, - 0x8e, 0x5c, 0x4a, 0x6e, 0xcb, 0x98, 0x7f, 0xa3, 0x33, 0xa8, 0xbd, 0xa4, 0x46, 0xbc, 0x36, 0x37, - 0x9a, 0x7a, 0x66, 0xd7, 0x35, 0xcf, 0x47, 0xeb, 0x71, 0x3f, 0xfe, 0x5f, 0xb8, 0xfa, 0x92, 0xc6, - 0x04, 0xfa, 0xa5, 0x02, 0xb7, 0xa3, 0xd0, 0x61, 0x2a, 0x3e, 0xc7, 0xb3, 0x08, 0x6d, 0xe4, 0xef, - 0xaa, 0xdb, 0xf5, 0x9d, 0xe3, 0x6b, 0xc8, 0x6f, 0xae, 0xf1, 0xd0, 0xb3, 0x08, 0xbe, 0xe9, 0x2e, - 0x68, 0xa5, 0xa8, 0x05, 0x37, 0x9c, 0x09, 0x0d, 0x0d, 0x61, 0x05, 0x86, 0x1c, 0xd4, 0x28, 0x70, - 0xb9, 0x6c, 0xb2, 0xae, 0x94, 0xad, 0xa2, 0x73, 0x58, 0x77, 0xbc, 0x89, 0x1b, 0x1a, 0x43, 0x7e, - 0xc7, 0xa1, 0x8d, 0xe2, 0x52, 0x97, 0xdf, 0x05, 0x52, 0x3a, 0x64, 0x70, 0xe2, 0xc6, 0x44, 0x71, - 0xcd, 0x49, 0x50, 0x4c, 0x91, 0x01, 0x71, 0xbc, 0x90, 0x18, 0xcc, 0x27, 0xd2, 0x46, 0x49, 0x28, - 0x52, 0xb4, 0xb1, 0xed, 0x4f, 0xf5, 0x16, 0x54, 0x13, 0x62, 0x46, 0x65, 0xc8, 0xf7, 0x8e, 0x7a, - 0x5d, 0x6d, 0x0d, 0x01, 0x14, 0x3b, 0x7b, 0xf8, 0xe8, 0x68, 0x20, 0x6e, 0x06, 0xfb, 0x87, 0xed, - 0x27, 0x5d, 0x2d, 0xa7, 0x77, 0xa1, 0x96, 0x5c, 0x10, 0x21, 0xa8, 0x9f, 0xf4, 0x9e, 0xf6, 0x8e, - 0x9e, 0xf5, 0x8c, 0xc3, 0xa3, 0x93, 0xde, 0x80, 0xdd, 0x29, 0xea, 0x00, 0xed, 0xde, 0xf3, 0x29, - 0xbd, 0x0e, 0x95, 0xde, 0x51, 0x44, 0x2a, 0xcd, 0x9c, 0xa6, 0xe8, 0xff, 0xae, 0xc2, 0xd6, 0x22, - 0xd9, 0x23, 0x0b, 0xf2, 0x4c, 0x8f, 0xf2, 0x56, 0xf7, 0xee, 0xd5, 0xc8, 0xd1, 0x99, 0xf9, 0xfa, - 0xa6, 0x74, 0xe3, 0x15, 0xcc, 0xbf, 0x91, 0x01, 0xc5, 0xb1, 0x79, 0x4a, 0xc6, 0xb4, 0xa1, 0xf2, - 0xbc, 0xc7, 0x93, 0xeb, 0xac, 0x7d, 0xc0, 0x91, 0x44, 0xd2, 0x43, 0xc2, 0xa2, 0x01, 0x54, 0xcf, - 0x3c, 0x1a, 0x52, 0x21, 0x3a, 0xe9, 0x3b, 0x77, 0x32, 0xae, 0xb2, 0x37, 0x9d, 0x89, 0x93, 0x30, - 0xcd, 0x07, 0x50, 0x4d, 0x2c, 0xb6, 0x20, 0x67, 0xb1, 0x95, 0xcc, 0x59, 0x54, 0x92, 0x09, 0x88, - 0x47, 0xf3, 0x3a, 0x60, 0x32, 0x62, 0x46, 0xb0, 0x77, 0xd4, 0x1f, 0x88, 0xdb, 0xe1, 0x13, 0x7c, - 0x74, 0x72, 0xac, 0x29, 0xac, 0x71, 0xd0, 0xee, 0x3f, 0xd5, 0x72, 0xb1, 0x8d, 0xa8, 0x7a, 0x07, - 0xaa, 0x09, 0xbe, 0x50, 0x13, 0xca, 0x8c, 0x33, 0xd7, 0x74, 0x88, 0x64, 0x20, 0xa6, 0x99, 0xdf, - 0x34, 0x2d, 0x2b, 0x20, 0x94, 0x4a, 0x3e, 0x22, 0x52, 0x7f, 0x01, 0x95, 0xdd, 0x5e, 0x5f, 0x42, - 0x34, 0xa0, 0x44, 0x49, 0xc0, 0xfe, 0x37, 0xcf, 0x3e, 0x55, 0x70, 0x44, 0x32, 0x70, 0x4a, 0xcc, - 0x60, 0x78, 0x46, 0xa8, 0x3c, 0xcf, 0x63, 0x9a, 0xcd, 0xf2, 0x78, 0x16, 0x47, 0xe8, 0xae, 0x82, - 0x23, 0x52, 0xff, 0x9f, 0x12, 0xc0, 0x34, 0xa3, 0x80, 0xea, 0x90, 0x8b, 0x7d, 0x70, 0xce, 0xb6, - 0x98, 0x1d, 0x70, 0x6e, 0xa5, 0x1d, 0x70, 0x4e, 0x77, 0xe0, 0xa6, 0x43, 0x47, 0xbe, 0x39, 0x3c, - 0x37, 0x64, 0x22, 0x40, 0x6c, 0x55, 0xee, 0xcf, 0x6a, 0xf8, 0x86, 0xec, 0x94, 0x3b, 0x51, 0xe0, - 0x1e, 0x80, 0x4a, 0xdc, 0x0b, 0xee, 0x7b, 0xaa, 0x3b, 0x9f, 0x2d, 0x9d, 0xe9, 0x68, 0x75, 0xdd, - 0x0b, 0x61, 0x2b, 0x0c, 0x06, 0x19, 0x00, 0x16, 0xb9, 0xb0, 0x87, 0xc4, 0x60, 0xa0, 0x05, 0x0e, - 0xfa, 0xc5, 0xf2, 0xa0, 0xbb, 0x1c, 0x23, 0x86, 0xae, 0x58, 0x11, 0x8d, 0x7a, 0x50, 0x09, 0x08, - 0xf5, 0x26, 0xc1, 0x90, 0x08, 0x07, 0x94, 0xfd, 0x32, 0x82, 0xa3, 0x79, 0x78, 0x0a, 0x81, 0x76, - 0xa1, 0xc8, 0xfd, 0x0e, 0xf3, 0x30, 0xea, 0x77, 0xa6, 0x4d, 0xd3, 0x60, 0xdc, 0x93, 0x60, 0x39, - 0x17, 0x3d, 0x81, 0x92, 0x60, 0x91, 0x36, 0xca, 0x1c, 0xe6, 0xc3, 0xac, 0x4e, 0x91, 0xcf, 0xc2, - 0xd1, 0x6c, 0xa6, 0xd5, 0x09, 0x25, 0x41, 0xa3, 0x22, 0xb4, 0xca, 0xbe, 0xd1, 0xf7, 0xa0, 0x22, - 0xce, 0x60, 0xcb, 0x0e, 0x1a, 0x20, 0x8c, 0x93, 0x37, 0xec, 0xda, 0x01, 0x7a, 0x0f, 0xaa, 0x22, - 0x9e, 0x32, 0xb8, 0x57, 0xa8, 0xf2, 0x6e, 0x10, 0x4d, 0xc7, 0xcc, 0x37, 0x88, 0x01, 0x24, 0x08, - 0xc4, 0x80, 0x5a, 0x3c, 0x80, 0x04, 0x01, 0x1f, 0xf0, 0x07, 0xb0, 0xc1, 0xa3, 0xd0, 0x51, 0xe0, - 0x4d, 0x7c, 0x83, 0xdb, 0xd4, 0x3a, 0x1f, 0xb4, 0xce, 0x9a, 0x9f, 0xb0, 0xd6, 0x1e, 0x33, 0xae, - 0x3b, 0x50, 0x7e, 0xe5, 0x9d, 0x8a, 0x01, 0x75, 0xb1, 0x0f, 0x5e, 0x79, 0xa7, 0x51, 0x57, 0x1c, - 0x25, 0x6c, 0xa4, 0xa3, 0x84, 0x6f, 0xe0, 0xd6, 0xfc, 0x71, 0xc7, 0xa3, 0x05, 0xed, 0xfa, 0xd1, - 0xc2, 0x96, 0xbb, 0xc8, 0x0f, 0x7f, 0x09, 0xaa, 0xe5, 0xd2, 0xc6, 0xe6, 0x52, 0xc6, 0x11, 0xef, - 0x63, 0xcc, 0x26, 0x37, 0x3f, 0x81, 0x72, 0x64, 0x7d, 0xcb, 0xf8, 0xa5, 0xe6, 0x43, 0xa8, 0xa7, - 0x6d, 0x77, 0x29, 0xaf, 0xf6, 0xcf, 0x39, 0xa8, 0xc4, 0x56, 0x8a, 0x5c, 0xb8, 0xc1, 0xa5, 0xc8, - 0x42, 0x34, 0x63, 0x6a, 0xf4, 0x22, 0x30, 0xfc, 0x3c, 0xe3, 0xff, 0x6a, 0x47, 0x08, 0xf2, 0x16, - 0x2a, 0x77, 0x00, 0x8a, 0x91, 0xa7, 0xeb, 0x7d, 0x0d, 0x1b, 0x63, 0xdb, 0x9d, 0x5c, 0x26, 0xd6, - 0x12, 0x11, 0xdd, 0x1f, 0x66, 0x5c, 0xeb, 0x80, 0xcd, 0x9e, 0xae, 0x51, 0x1f, 0xa7, 0x68, 0xb4, - 0x07, 0x05, 0xdf, 0x0b, 0xc2, 0xe8, 0x90, 0xca, 0x7a, 0x7c, 0x1c, 0x7b, 0x41, 0x78, 0x68, 0xfa, - 0x3e, 0xbb, 0x98, 0x08, 0x00, 0xfd, 0xdb, 0x1c, 0xdc, 0x5a, 0xfc, 0xc7, 0x50, 0x0f, 0xd4, 0xa1, - 0x3f, 0x91, 0x42, 0x7a, 0xb8, 0xac, 0x90, 0x3a, 0xfe, 0x64, 0xca, 0x3f, 0x03, 0x42, 0xcf, 0xa0, - 0xe8, 0x10, 0xc7, 0x0b, 0xae, 0xa4, 0x2c, 0x1e, 0x2d, 0x0b, 0x79, 0xc8, 0x67, 0x4f, 0x51, 0x25, - 0x1c, 0xc2, 0x50, 0x96, 0xd6, 0x4b, 0xa5, 0x9f, 0x5c, 0x32, 0x75, 0x14, 0x41, 0xe2, 0x18, 0x47, - 0xff, 0x04, 0x6e, 0x2e, 0xfc, 0x2b, 0xe8, 0x77, 0x01, 0x86, 0xfe, 0xc4, 0xe0, 0xa9, 0x7d, 0x61, - 0x41, 0x2a, 0xae, 0x0c, 0xfd, 0x49, 0x9f, 0x37, 0xe8, 0x2f, 0xa0, 0xf1, 0x26, 0x7e, 0x99, 0xf7, - 0x11, 0x1c, 0x1b, 0xce, 0x29, 0x97, 0x81, 0x8a, 0xcb, 0xa2, 0xe1, 0xf0, 0x14, 0xe9, 0xb0, 0x1e, - 0x75, 0x9a, 0x97, 0x6c, 0x80, 0xca, 0x07, 0x54, 0xe5, 0x00, 0xf3, 0xf2, 0xf0, 0x54, 0xff, 0x55, - 0x0e, 0x36, 0x66, 0x58, 0x66, 0xd7, 0x33, 0xe1, 0xf1, 0xa2, 0x8b, 0xaf, 0xa0, 0x98, 0xfb, 0x1b, - 0xda, 0x56, 0x94, 0x32, 0xe5, 0xdf, 0xfc, 0xe0, 0xf3, 0x65, 0x3a, 0x33, 0x67, 0xfb, 0x6c, 0xfb, - 0x38, 0xa7, 0x76, 0x48, 0x79, 0x14, 0x52, 0xc0, 0x82, 0x40, 0xcf, 0xa1, 0x1e, 0x10, 0x7e, 0xe0, - 0x5a, 0x86, 0xb0, 0xb2, 0xc2, 0x52, 0x56, 0x26, 0x39, 0x64, 0xc6, 0x86, 0xd7, 0x23, 0x24, 0x46, - 0x51, 0xf4, 0x0c, 0xd6, 0xad, 0x2b, 0xd7, 0x74, 0xec, 0xa1, 0x44, 0x2e, 0xae, 0x8c, 0x5c, 0x93, - 0x40, 0x1c, 0x58, 0x7f, 0x00, 0xd5, 0x44, 0x27, 0xfb, 0x63, 0x3c, 0xdc, 0x92, 0x32, 0x11, 0x44, - 0xda, 0x5b, 0x14, 0xa4, 0xb7, 0xd0, 0x4f, 0xa1, 0x9a, 0xd8, 0x17, 0xcb, 0x4c, 0x65, 0xf2, 0x0c, - 0x3d, 0x2e, 0xcf, 0x02, 0xce, 0x85, 0x1e, 0xba, 0x0d, 0x25, 0x16, 0xea, 0x18, 0xb6, 0xcf, 0x25, - 0x5a, 0xc1, 0x45, 0x46, 0xee, 0xfb, 0xfa, 0x6f, 0x72, 0x50, 0x4f, 0x6f, 0xe9, 0xc8, 0x8e, 0x7c, - 0x12, 0xd8, 0x9e, 0x95, 0xb0, 0xa3, 0x63, 0xde, 0xc0, 0x6c, 0x85, 0x75, 0x7f, 0x33, 0xf1, 0x42, - 0x33, 0xb2, 0x95, 0xa1, 0x3f, 0xf9, 0x23, 0x46, 0xcf, 0xd8, 0xa0, 0x3a, 0x63, 0x83, 0xe8, 0x03, - 0x40, 0xd2, 0x94, 0xc6, 0xb6, 0x63, 0x87, 0xc6, 0xe9, 0x55, 0x48, 0x84, 0x8e, 0x55, 0xac, 0x89, - 0x9e, 0x03, 0xd6, 0xf1, 0x25, 0x6b, 0x67, 0x86, 0xe7, 0x79, 0x8e, 0x41, 0x87, 0x5e, 0x40, 0x0c, - 0xd3, 0x7a, 0xc5, 0x6f, 0x2d, 0x2a, 0xae, 0x7a, 0x9e, 0xd3, 0x67, 0x6d, 0x6d, 0xeb, 0x15, 0x3b, - 0xf9, 0x86, 0xfe, 0x84, 0x92, 0xd0, 0x60, 0x3f, 0x3c, 0x58, 0xa8, 0x60, 0x10, 0x4d, 0x1d, 0x7f, - 0x42, 0xd1, 0xef, 0xc3, 0x7a, 0x34, 0x80, 0x1f, 0x7e, 0xf2, 0xd4, 0xad, 0xc9, 0x21, 0xbc, 0x0d, - 0xe9, 0x50, 0x3b, 0x26, 0xc1, 0x90, 0xb8, 0xe1, 0xc0, 0x1e, 0x9e, 0xb3, 0xf3, 0x5d, 0xd9, 0x56, - 0x70, 0xaa, 0xed, 0xab, 0x7c, 0xb9, 0xa4, 0x95, 0x71, 0xb4, 0x9a, 0x43, 0x1c, 0xaa, 0xff, 0x0c, - 0x0a, 0x3c, 0x44, 0x60, 0x32, 0xe1, 0xc7, 0x2b, 0x3f, 0x7d, 0x65, 0x68, 0xc9, 0x1a, 0xf8, 0xd9, - 0xfb, 0x3d, 0xa8, 0x70, 0xd9, 0x27, 0x22, 0x7a, 0x1e, 0x77, 0xf2, 0xce, 0x26, 0x94, 0x03, 0x62, - 0x5a, 0x9e, 0x3b, 0x8e, 0x12, 0x3e, 0x31, 0xad, 0x7f, 0x03, 0x45, 0x71, 0xce, 0x5c, 0x03, 0xff, - 0x43, 0x40, 0xe2, 0x7f, 0x33, 0x7d, 0x3a, 0x36, 0xa5, 0x32, 0x0a, 0xe5, 0xaf, 0x8c, 0xa2, 0xe7, - 0x78, 0xda, 0xa1, 0xff, 0xa7, 0x22, 0xe2, 0x51, 0xf1, 0xfe, 0xc3, 0x02, 0x57, 0x66, 0xe4, 0xec, - 0xb6, 0x2c, 0x12, 0x4d, 0x11, 0x89, 0xf6, 0xa1, 0x28, 0xc3, 0xce, 0xdc, 0xaa, 0xcf, 0x67, 0x12, - 0x20, 0x4a, 0x3b, 0x13, 0x79, 0x21, 0x5f, 0x36, 0xed, 0x4c, 0x44, 0xda, 0x99, 0xb0, 0xdb, 0xa4, - 0x0c, 0x88, 0x05, 0x5c, 0x9e, 0xc7, 0xc3, 0x55, 0x2b, 0xce, 0xed, 0x13, 0xfd, 0xbf, 0x95, 0xd8, - 0x4d, 0x45, 0x39, 0x78, 0xf4, 0x35, 0x94, 0xd9, 0x8e, 0x37, 0x1c, 0xd3, 0x97, 0x2f, 0xca, 0x9d, - 0xd5, 0xd2, 0xfb, 0xd1, 0x21, 0x26, 0xc2, 0xd9, 0x92, 0x2f, 0x28, 0xe6, 0xee, 0xd8, 0x55, 0x22, - 0x72, 0x77, 0xec, 0x1b, 0xbd, 0x0f, 0x75, 0x73, 0x12, 0x7a, 0x86, 0x69, 0x5d, 0x90, 0x20, 0xb4, - 0x29, 0x91, 0xba, 0x5f, 0x67, 0xad, 0xed, 0xa8, 0xb1, 0xf9, 0x19, 0xd4, 0x92, 0x98, 0x6f, 0x0b, - 0x33, 0x0a, 0xc9, 0x30, 0xe3, 0x4f, 0x01, 0xa6, 0xf9, 0x2c, 0x66, 0x23, 0xe4, 0xd2, 0x66, 0xb7, - 0x7a, 0x79, 0x77, 0x2d, 0xe0, 0x32, 0x6b, 0xe8, 0xb0, 0xfb, 0x54, 0x3a, 0xd9, 0x5e, 0x88, 0x92, - 0xed, 0x6c, 0x33, 0xb3, 0xfd, 0x77, 0x6e, 0x8f, 0xc7, 0x71, 0x8e, 0xad, 0xe2, 0x79, 0xce, 0x53, - 0xde, 0xa0, 0xff, 0x36, 0x27, 0x6c, 0x45, 0x3c, 0x9b, 0x64, 0xba, 0xbb, 0xbc, 0x2b, 0x55, 0x3f, - 0x00, 0xa0, 0xa1, 0x19, 0xb0, 0x98, 0xc9, 0x8c, 0xb2, 0x7c, 0xcd, 0xb9, 0x6c, 0xfd, 0x20, 0xaa, - 0xe3, 0xc0, 0x15, 0x39, 0xba, 0x1d, 0xa2, 0xcf, 0xa1, 0x36, 0xf4, 0x1c, 0x7f, 0x4c, 0xe4, 0xe4, - 0xc2, 0x5b, 0x27, 0x57, 0xe3, 0xf1, 0xed, 0x30, 0x91, 0x5b, 0x2c, 0x5e, 0x37, 0xb7, 0xf8, 0x1b, - 0x45, 0xbc, 0xfe, 0x24, 0x1f, 0x9f, 0xd0, 0x68, 0x41, 0x85, 0xc3, 0x93, 0x15, 0x5f, 0xb2, 0xbe, - 0xab, 0xbc, 0xa1, 0xf9, 0x79, 0x96, 0x7a, 0x82, 0x37, 0x47, 0xb1, 0xff, 0xa6, 0x42, 0x25, 0x7e, - 0xf8, 0x99, 0xd3, 0xfd, 0xa7, 0x50, 0x89, 0x8b, 0x68, 0xa4, 0x83, 0xf8, 0x4e, 0xf5, 0xc4, 0x83, - 0xd1, 0x4b, 0x40, 0xe6, 0x68, 0x14, 0x47, 0xa7, 0xc6, 0x84, 0x9a, 0xa3, 0xe8, 0xd9, 0xed, 0xd3, - 0x25, 0xe4, 0x10, 0x1d, 0x67, 0x27, 0x6c, 0x3e, 0xd6, 0xcc, 0xd1, 0x28, 0xd5, 0x82, 0xfe, 0x0c, - 0x6e, 0xa6, 0xd7, 0x30, 0x4e, 0xaf, 0x0c, 0xdf, 0xb6, 0xe4, 0x1d, 0x79, 0x6f, 0xd9, 0xb7, 0xaf, - 0x56, 0x0a, 0xfe, 0xcb, 0xab, 0x63, 0xdb, 0x12, 0x32, 0x47, 0xc1, 0x5c, 0x47, 0xf3, 0x2f, 0xe0, - 0xf6, 0x1b, 0x86, 0x2f, 0xd0, 0x41, 0x2f, 0x5d, 0xd3, 0xb1, 0xba, 0x10, 0x12, 0xda, 0xfb, 0xb5, - 0x22, 0x9e, 0xe8, 0xd2, 0x32, 0x69, 0x27, 0xc3, 0xea, 0x7b, 0x19, 0xd7, 0xe9, 0x1c, 0x9f, 0x08, - 0x78, 0x1e, 0x49, 0x7f, 0x35, 0x13, 0x49, 0x67, 0x8d, 0x9f, 0x44, 0x40, 0x2a, 0x80, 0x24, 0x82, - 0xfe, 0x2f, 0x2a, 0x94, 0x23, 0x74, 0x7e, 0xc3, 0xbd, 0xa2, 0x21, 0x71, 0x8c, 0x38, 0xfd, 0xa6, - 0x60, 0x10, 0x4d, 0x3c, 0x29, 0xf4, 0x3d, 0xa8, 0xb0, 0x8b, 0xb4, 0xe8, 0xce, 0xf1, 0xee, 0x32, - 0x6b, 0xe0, 0x9d, 0xef, 0x41, 0x35, 0xf4, 0x42, 0x73, 0x6c, 0x84, 0xfc, 0x78, 0x57, 0xc5, 0x6c, - 0xde, 0xc4, 0x0f, 0x77, 0xf4, 0x43, 0xd8, 0x0c, 0xcf, 0x02, 0x2f, 0x0c, 0xc7, 0x2c, 0xb4, 0xe4, - 0x81, 0x8e, 0x88, 0x4b, 0xf2, 0x58, 0x8b, 0x3b, 0x44, 0x00, 0x44, 0x99, 0xf7, 0x9e, 0x0e, 0x66, - 0xa6, 0xcb, 0x9d, 0x48, 0x1e, 0xaf, 0xc7, 0xad, 0xcc, 0xb4, 0xd9, 0xe1, 0xe9, 0x8b, 0x00, 0x82, - 0xfb, 0x0a, 0x05, 0x47, 0x24, 0x32, 0x60, 0xc3, 0x21, 0x26, 0x9d, 0x04, 0xc4, 0x32, 0x5e, 0xda, - 0x64, 0x6c, 0x89, 0xc4, 0x44, 0x3d, 0xf3, 0xed, 0x20, 0x12, 0x4b, 0xeb, 0x31, 0x9f, 0x8d, 0xeb, - 0x11, 0x9c, 0xa0, 0x59, 0xe4, 0x20, 0xbe, 0xd0, 0x06, 0x54, 0xfb, 0xcf, 0xfb, 0x83, 0xee, 0xa1, - 0x71, 0x78, 0xb4, 0xdb, 0x95, 0x65, 0x3b, 0xfd, 0x2e, 0x16, 0xa4, 0xc2, 0xfa, 0x07, 0x47, 0x83, - 0xf6, 0x81, 0x31, 0xd8, 0xef, 0x3c, 0xed, 0x6b, 0x39, 0x74, 0x13, 0x36, 0x07, 0x7b, 0xf8, 0x68, - 0x30, 0x38, 0xe8, 0xee, 0x1a, 0xc7, 0x5d, 0xbc, 0x7f, 0xb4, 0xdb, 0xd7, 0x54, 0x84, 0xa0, 0x3e, - 0x6d, 0x1e, 0xec, 0x1f, 0x76, 0xb5, 0x3c, 0xaa, 0x42, 0xe9, 0xb8, 0x8b, 0x3b, 0xdd, 0xde, 0x40, - 0x2b, 0xe8, 0xbf, 0x52, 0xa1, 0x9a, 0xd0, 0x22, 0x33, 0xe4, 0x80, 0x8a, 0x6b, 0x48, 0x1e, 0xb3, - 0x4f, 0xfe, 0xcc, 0x68, 0x0e, 0xcf, 0x84, 0x76, 0xf2, 0x58, 0x10, 0xfc, 0xea, 0x61, 0x5e, 0x26, - 0xf6, 0x79, 0x1e, 0x97, 0x1d, 0xf3, 0x52, 0x80, 0x7c, 0x1f, 0x6a, 0xe7, 0x24, 0x70, 0xc9, 0x58, - 0xf6, 0x0b, 0x8d, 0x54, 0x45, 0x9b, 0x18, 0xb2, 0x0d, 0x9a, 0x1c, 0x32, 0x85, 0x11, 0xea, 0xa8, - 0x8b, 0xf6, 0xc3, 0x08, 0x6c, 0x0b, 0x0a, 0xa2, 0xbb, 0x24, 0xd6, 0xe7, 0x04, 0x3b, 0xa6, 0xe8, - 0x6b, 0xd3, 0xe7, 0x21, 0x5f, 0x1e, 0xf3, 0x6f, 0x74, 0x3a, 0xaf, 0x9f, 0x22, 0xd7, 0xcf, 0x83, - 0xe5, 0xcd, 0xf9, 0x4d, 0x2a, 0x3a, 0x8b, 0x55, 0x54, 0x02, 0x15, 0x47, 0xb5, 0x2e, 0x9d, 0x76, - 0x67, 0x8f, 0xa9, 0x65, 0x1d, 0x2a, 0x87, 0xed, 0x9f, 0x1a, 0x27, 0x7d, 0x9e, 0xd5, 0x46, 0x1a, - 0xd4, 0x9e, 0x76, 0x71, 0xaf, 0x7b, 0x20, 0x5b, 0x54, 0xb4, 0x05, 0x9a, 0x6c, 0x99, 0x8e, 0xcb, - 0x33, 0x04, 0xf1, 0x59, 0x40, 0x65, 0xc8, 0xf7, 0x9f, 0xb5, 0x8f, 0xb5, 0xa2, 0xfe, 0x5f, 0x39, - 0xd8, 0x10, 0xc7, 0x42, 0xfc, 0x2a, 0xff, 0xe6, 0x57, 0xc9, 0x64, 0x96, 0x27, 0x97, 0xce, 0xf2, - 0x44, 0x41, 0x28, 0x3f, 0xd5, 0xd5, 0x69, 0x10, 0xca, 0xb3, 0x43, 0x29, 0x8f, 0x9f, 0x5f, 0xc6, - 0xe3, 0x37, 0xa0, 0xe4, 0x10, 0x1a, 0xeb, 0xad, 0x82, 0x23, 0x12, 0xd9, 0x50, 0x35, 0x5d, 0xd7, - 0x0b, 0x4d, 0x91, 0x3a, 0x2d, 0x2e, 0x75, 0x18, 0xce, 0xfc, 0xe3, 0x56, 0x7b, 0x8a, 0x24, 0x1c, - 0x73, 0x12, 0xbb, 0xf9, 0x13, 0xd0, 0x66, 0x07, 0x2c, 0x73, 0x1c, 0xfe, 0xe0, 0xe3, 0xe9, 0x69, - 0x48, 0xd8, 0xbe, 0x90, 0x6f, 0x0e, 0xda, 0x1a, 0x23, 0xf0, 0x49, 0xaf, 0xb7, 0xdf, 0x7b, 0xa2, - 0x29, 0x08, 0xa0, 0xd8, 0xfd, 0xe9, 0xfe, 0xa0, 0xbb, 0xab, 0xe5, 0x76, 0x7e, 0xbd, 0x09, 0x45, - 0xc1, 0x24, 0xfa, 0x56, 0x46, 0x02, 0xc9, 0x8a, 0x4f, 0xf4, 0x93, 0xa5, 0x23, 0xea, 0x54, 0x15, - 0x69, 0xf3, 0xd1, 0xca, 0xf3, 0xe5, 0xeb, 0xdb, 0x1a, 0xfa, 0x1b, 0x05, 0x6a, 0xa9, 0x97, 0xb7, - 0xac, 0xa9, 0xe3, 0x05, 0x05, 0xa6, 0xcd, 0x1f, 0xaf, 0x34, 0x37, 0xe6, 0xe5, 0x97, 0x0a, 0x54, - 0x13, 0xa5, 0x95, 0xe8, 0xc1, 0x2a, 0xe5, 0x98, 0x82, 0x93, 0xcf, 0x56, 0xaf, 0xe4, 0xd4, 0xd7, - 0x3e, 0x52, 0xd0, 0x5f, 0x2b, 0x50, 0x4d, 0x14, 0x19, 0x66, 0x66, 0x65, 0xbe, 0x24, 0x32, 0x33, - 0x2b, 0x8b, 0x6a, 0x1a, 0xd7, 0xd0, 0x5f, 0x2a, 0x50, 0x89, 0x0b, 0x06, 0xd1, 0xfd, 0xe5, 0x4b, - 0x0c, 0x05, 0x13, 0x9f, 0xae, 0x5a, 0x9b, 0xa8, 0xaf, 0xa1, 0x3f, 0x87, 0x72, 0x54, 0x5d, 0x87, - 0xb2, 0x9e, 0x5e, 0x33, 0xa5, 0x7b, 0xcd, 0xfb, 0x4b, 0xcf, 0x4b, 0x2e, 0x1f, 0x95, 0xbc, 0x65, - 0x5e, 0x7e, 0xa6, 0x38, 0xaf, 0x79, 0x7f, 0xe9, 0x79, 0xf1, 0xf2, 0xcc, 0x12, 0x12, 0x95, 0x71, - 0x99, 0x2d, 0x61, 0xbe, 0x24, 0x2f, 0xb3, 0x25, 0x2c, 0x2a, 0xc4, 0x13, 0x8c, 0x24, 0x6a, 0xeb, - 0x32, 0x33, 0x32, 0x5f, 0xbf, 0x97, 0x99, 0x91, 0x05, 0xa5, 0x7c, 0xfa, 0x1a, 0xfa, 0x85, 0x92, - 0xbc, 0x17, 0xdc, 0x5f, 0xba, 0x84, 0x6c, 0x49, 0x93, 0x9c, 0x2b, 0x62, 0xe3, 0x1b, 0xf4, 0x17, - 0x32, 0x8b, 0x21, 0x2a, 0xd0, 0xd0, 0x32, 0x60, 0xa9, 0xa2, 0xb5, 0xe6, 0x27, 0xab, 0x1d, 0x36, - 0x9c, 0x89, 0xbf, 0x52, 0x00, 0xa6, 0xb5, 0x6a, 0x99, 0x99, 0x98, 0x2b, 0x92, 0x6b, 0x3e, 0x58, - 0x61, 0x66, 0x72, 0x83, 0x44, 0xb5, 0x34, 0x99, 0x37, 0xc8, 0x4c, 0x2d, 0x5d, 0xe6, 0x0d, 0x32, - 0x5b, 0x07, 0xa7, 0xaf, 0xa1, 0x7f, 0x52, 0x60, 0x73, 0xae, 0x96, 0x07, 0x3d, 0xba, 0x66, 0x39, - 0x57, 0xf3, 0x8b, 0xd5, 0x01, 0x22, 0xd6, 0xb6, 0x95, 0x8f, 0x14, 0xf4, 0xb7, 0x0a, 0xac, 0xa7, - 0xeb, 0x1f, 0x32, 0x9f, 0x52, 0x0b, 0xaa, 0x82, 0x9a, 0x0f, 0x57, 0x9b, 0x1c, 0x4b, 0xeb, 0xef, - 0x15, 0xa8, 0xa7, 0x4b, 0x61, 0xd0, 0xc3, 0xe5, 0xdc, 0xc2, 0x0c, 0x43, 0x9f, 0xaf, 0x38, 0x3b, - 0xe2, 0xe8, 0xcb, 0xd2, 0x1f, 0x17, 0x44, 0xf4, 0x56, 0xe4, 0x3f, 0x3f, 0xfa, 0xff, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x2c, 0x87, 0xc3, 0x62, 0x98, 0x33, 0x00, 0x00, + 0xa0, 0x70, 0x61, 0x8e, 0x27, 0x84, 0xb3, 0x5c, 0xdd, 0xf9, 0xe1, 0xdb, 0xcc, 0x43, 0x9a, 0xe8, + 0x54, 0x0e, 0x58, 0xcc, 0xff, 0x2c, 0xf7, 0xa9, 0xa2, 0x3f, 0x80, 0x6a, 0x82, 0x6f, 0x54, 0x07, + 0x38, 0xe9, 0xed, 0x76, 0x07, 0xdd, 0xce, 0xa0, 0xbb, 0xab, 0xad, 0xa1, 0x75, 0xa8, 0x9c, 0xf4, + 0xf6, 0xba, 0xed, 0x83, 0xc1, 0xde, 0x73, 0x4d, 0x41, 0x55, 0x28, 0x45, 0x44, 0x4e, 0xbf, 0x04, + 0x84, 0xc9, 0xd0, 0xbb, 0x20, 0x01, 0x33, 0x64, 0xa9, 0x55, 0x74, 0x1b, 0x4a, 0xa1, 0x49, 0xcf, + 0x0d, 0xdb, 0x92, 0x3c, 0x17, 0x19, 0xb9, 0x6f, 0xa1, 0x7d, 0x28, 0x9e, 0x99, 0xae, 0x35, 0x7e, + 0x3b, 0xdf, 0x69, 0x51, 0x33, 0xf0, 0x3d, 0x3e, 0x11, 0x4b, 0x00, 0x66, 0xdd, 0xa9, 0x95, 0x85, + 0x02, 0xf4, 0xe7, 0xa0, 0xf5, 0x43, 0x33, 0x08, 0x93, 0xec, 0x74, 0x21, 0xcf, 0xd6, 0x97, 0x16, + 0xbd, 0xcc, 0x9a, 0x62, 0x67, 0x62, 0x3e, 0x5d, 0xff, 0xdf, 0x1c, 0x6c, 0x26, 0xb0, 0xa5, 0xa5, + 0x3e, 0x83, 0x62, 0x40, 0xe8, 0x64, 0x1c, 0x72, 0xf8, 0xfa, 0xce, 0xa3, 0x8c, 0xf0, 0x73, 0x48, + 0x2d, 0xcc, 0x61, 0xb0, 0x84, 0x43, 0xdb, 0xa0, 0x89, 0x19, 0x06, 0x09, 0x02, 0x2f, 0x30, 0x1c, + 0x3a, 0xe2, 0x52, 0xab, 0xe0, 0xba, 0x68, 0xef, 0xb2, 0xe6, 0x43, 0x3a, 0x4a, 0x48, 0x55, 0xbd, + 0xa6, 0x54, 0x91, 0x09, 0x9a, 0x4b, 0xc2, 0xd7, 0x5e, 0x70, 0x6e, 0x30, 0xd1, 0x06, 0xb6, 0x45, + 0x1a, 0x79, 0x0e, 0xfa, 0x49, 0x46, 0xd0, 0x9e, 0x98, 0x7e, 0x24, 0x67, 0xe3, 0x0d, 0x37, 0xdd, + 0xa0, 0xff, 0x00, 0x8a, 0xe2, 0x9f, 0x32, 0x4b, 0xea, 0x9f, 0x74, 0x3a, 0xdd, 0x7e, 0x5f, 0x5b, + 0x43, 0x15, 0x28, 0xe0, 0xee, 0x00, 0x33, 0x0b, 0xab, 0x40, 0xe1, 0x71, 0x7b, 0xd0, 0x3e, 0xd0, + 0x72, 0xfa, 0xf7, 0x61, 0xe3, 0x99, 0x69, 0x87, 0x59, 0x8c, 0x4b, 0xf7, 0x40, 0x9b, 0x8e, 0x95, + 0xda, 0xd9, 0x4f, 0x69, 0x27, 0xbb, 0x68, 0xba, 0x97, 0x76, 0x38, 0xa3, 0x0f, 0x0d, 0x54, 0x12, + 0x04, 0x52, 0x05, 0xec, 0x53, 0x7f, 0x0d, 0x1b, 0xfd, 0xd0, 0xf3, 0x33, 0x59, 0xfe, 0x8f, 0xa0, + 0xc4, 0x4e, 0x1b, 0x6f, 0x12, 0x4a, 0xd3, 0xbf, 0xd3, 0x12, 0xa7, 0x51, 0x2b, 0x3a, 0x8d, 0x5a, + 0xbb, 0xf2, 0xb4, 0xc2, 0xd1, 0x48, 0x74, 0x0b, 0x8a, 0xd4, 0x1e, 0xb9, 0xe6, 0x58, 0x7a, 0x0b, + 0x49, 0xe9, 0x88, 0x19, 0x79, 0xb4, 0xb0, 0x34, 0xfc, 0x0e, 0xa0, 0x5d, 0x42, 0xc3, 0xc0, 0xbb, + 0xca, 0xc4, 0xcf, 0x16, 0x14, 0x5e, 0x7a, 0xc1, 0x50, 0x6c, 0xc4, 0x32, 0x16, 0x04, 0xdb, 0x54, + 0x29, 0x10, 0x89, 0xfd, 0x11, 0xa0, 0x7d, 0x97, 0x9d, 0x29, 0xd9, 0x14, 0xf1, 0x0f, 0x39, 0xb8, + 0x91, 0x1a, 0x2f, 0x95, 0xb1, 0xfa, 0x3e, 0x64, 0x8e, 0x69, 0x42, 0xc5, 0x3e, 0x44, 0x47, 0x50, + 0x14, 0x23, 0xa4, 0x24, 0xef, 0x2f, 0x01, 0x24, 0x8e, 0x29, 0x09, 0x27, 0x61, 0x16, 0x1a, 0xbd, + 0xfa, 0x6e, 0x8d, 0xfe, 0x35, 0x68, 0xd1, 0xff, 0xa0, 0x6f, 0xd5, 0xcd, 0x57, 0x70, 0x63, 0xe8, + 0x8d, 0xc7, 0x64, 0xc8, 0xac, 0xc1, 0xb0, 0xdd, 0x90, 0x04, 0x17, 0xe6, 0xf8, 0xed, 0x76, 0x83, + 0xa6, 0xb3, 0xf6, 0xe5, 0x24, 0xfd, 0x05, 0x6c, 0x26, 0x16, 0x96, 0x8a, 0x78, 0x0c, 0x05, 0xca, + 0x1a, 0xa4, 0x26, 0x3e, 0x5e, 0x52, 0x13, 0x14, 0x8b, 0xe9, 0xfa, 0x0d, 0x01, 0xde, 0xbd, 0x20, + 0x6e, 0xfc, 0xb7, 0xf4, 0x5d, 0xd8, 0xec, 0x73, 0x33, 0xcd, 0x64, 0x87, 0x53, 0x13, 0xcf, 0xa5, + 0x4c, 0x7c, 0x0b, 0x50, 0x12, 0x45, 0x1a, 0xe2, 0x15, 0x6c, 0x74, 0x2f, 0xc9, 0x30, 0x13, 0x72, + 0x03, 0x4a, 0x43, 0xcf, 0x71, 0x4c, 0xd7, 0x6a, 0xe4, 0xee, 0xaa, 0xdb, 0x15, 0x1c, 0x91, 0xc9, + 0xbd, 0xa8, 0x66, 0xdd, 0x8b, 0xfa, 0xdf, 0x29, 0xa0, 0x4d, 0xd7, 0x96, 0x82, 0x64, 0xdc, 0x87, + 0x16, 0x03, 0x62, 0x6b, 0xd7, 0xb0, 0xa4, 0x64, 0x7b, 0xe4, 0x2e, 0x44, 0x3b, 0x09, 0x82, 0x84, + 0x3b, 0x52, 0xaf, 0xe9, 0x8e, 0xf4, 0x3d, 0xf8, 0x9d, 0x88, 0x9d, 0x7e, 0x18, 0x10, 0xd3, 0xb1, + 0xdd, 0xd1, 0xfe, 0xd1, 0x91, 0x4f, 0x04, 0xe3, 0x08, 0x41, 0xde, 0x32, 0x43, 0x53, 0x32, 0xc6, + 0xbf, 0xd9, 0xa6, 0x1f, 0x8e, 0x3d, 0x1a, 0x6f, 0x7a, 0x4e, 0xe8, 0xff, 0xa1, 0x42, 0x63, 0x0e, + 0x2a, 0x12, 0xef, 0x0b, 0x28, 0x50, 0x12, 0x4e, 0x7c, 0x69, 0x2a, 0xdd, 0xcc, 0x0c, 0x2f, 0xc6, + 0x6b, 0xf5, 0x19, 0x18, 0x16, 0x98, 0x68, 0x04, 0xe5, 0x30, 0xbc, 0x32, 0xa8, 0xfd, 0xf3, 0x28, + 0x20, 0x38, 0xb8, 0x2e, 0xfe, 0x80, 0x04, 0x8e, 0xed, 0x9a, 0xe3, 0xbe, 0xfd, 0x73, 0x82, 0x4b, + 0x61, 0x78, 0xc5, 0x3e, 0xd0, 0x73, 0x66, 0xf0, 0x96, 0xed, 0x4a, 0xb1, 0x77, 0x56, 0x5d, 0x25, + 0x21, 0x60, 0x2c, 0x10, 0x9b, 0x07, 0x50, 0xe0, 0xff, 0x69, 0x15, 0x43, 0xd4, 0x40, 0x0d, 0xc3, + 0x2b, 0xce, 0x54, 0x19, 0xb3, 0xcf, 0xe6, 0x43, 0xa8, 0x25, 0xff, 0x01, 0x33, 0xa4, 0x33, 0x62, + 0x8f, 0xce, 0x84, 0x81, 0x15, 0xb0, 0xa4, 0x98, 0x26, 0x5f, 0xdb, 0x96, 0x0c, 0x59, 0x0b, 0x58, + 0x10, 0xfa, 0xbf, 0xe6, 0xe0, 0xce, 0x02, 0xc9, 0x48, 0x63, 0x7d, 0x91, 0x32, 0xd6, 0x77, 0x24, + 0x85, 0xc8, 0xe2, 0x5f, 0xa4, 0x2c, 0xfe, 0x1d, 0x82, 0xb3, 0x6d, 0x73, 0x0b, 0x8a, 0xe4, 0xd2, + 0x0e, 0x89, 0x25, 0x45, 0x25, 0xa9, 0xc4, 0x76, 0xca, 0x5f, 0x77, 0x3b, 0x1d, 0xc2, 0x56, 0x27, + 0x20, 0x66, 0x48, 0xa4, 0x2b, 0x8f, 0xec, 0xff, 0x0e, 0x94, 0xcd, 0xf1, 0xd8, 0x1b, 0x4e, 0xd5, + 0x5a, 0xe2, 0xf4, 0xbe, 0x85, 0x9a, 0x50, 0x3e, 0xf3, 0x68, 0xe8, 0x9a, 0x0e, 0x91, 0xce, 0x2b, + 0xa6, 0xf5, 0x6f, 0x15, 0xb8, 0x39, 0x83, 0x27, 0xb5, 0x70, 0x0a, 0x75, 0x9b, 0x7a, 0x63, 0xfe, + 0x07, 0x8d, 0xc4, 0x0d, 0xef, 0xc7, 0xcb, 0x1d, 0x35, 0xfb, 0x11, 0x06, 0xbf, 0xf0, 0xad, 0xdb, + 0x49, 0x92, 0x5b, 0x1c, 0x5f, 0xdc, 0x92, 0x3b, 0x3d, 0x22, 0xf5, 0x7f, 0x54, 0xe0, 0xa6, 0x3c, + 0xe1, 0xb3, 0xff, 0xd1, 0x79, 0x96, 0x73, 0xef, 0x9a, 0x65, 0xbd, 0x01, 0xb7, 0x66, 0xf9, 0x92, + 0x3e, 0xff, 0xff, 0xf2, 0x80, 0xe6, 0x6f, 0x97, 0xe8, 0x7b, 0x50, 0xa3, 0xc4, 0xb5, 0x0c, 0x71, + 0x5e, 0x88, 0xa3, 0xac, 0x8c, 0xab, 0xac, 0x4d, 0x1c, 0x1c, 0x94, 0xb9, 0x40, 0x72, 0x29, 0xb9, + 0x2d, 0x63, 0xfe, 0x8d, 0xce, 0xa0, 0xf6, 0x92, 0x1a, 0xf1, 0xda, 0xdc, 0xa0, 0xea, 0x99, 0xdd, + 0xda, 0x3c, 0x1f, 0xad, 0xc7, 0xfd, 0xf8, 0x7f, 0xe1, 0xea, 0x4b, 0x1a, 0x13, 0xe8, 0x97, 0x0a, + 0xdc, 0x8e, 0xc2, 0x8a, 0xa9, 0xf8, 0x1c, 0xcf, 0x22, 0xb4, 0x91, 0xbf, 0xab, 0x6e, 0xd7, 0x77, + 0x8e, 0xaf, 0x21, 0xbf, 0xb9, 0xc6, 0x43, 0xcf, 0x22, 0xf8, 0xa6, 0xbb, 0xa0, 0x95, 0xa2, 0x16, + 0xdc, 0x70, 0x26, 0x34, 0x34, 0x84, 0x15, 0x18, 0x72, 0x50, 0xa3, 0xc0, 0xe5, 0xb2, 0xc9, 0xba, + 0x52, 0xb6, 0x8a, 0xce, 0x61, 0xdd, 0xf1, 0x26, 0x6e, 0x68, 0x0c, 0xf9, 0xfd, 0x87, 0x36, 0x8a, + 0x4b, 0x5d, 0x8c, 0x17, 0x48, 0xe9, 0x90, 0xc1, 0x89, 0xdb, 0x14, 0xc5, 0x35, 0x27, 0x41, 0x31, + 0x45, 0x06, 0xc4, 0xf1, 0x42, 0x62, 0x30, 0x7f, 0x49, 0x1b, 0x25, 0xa1, 0x48, 0xd1, 0xc6, 0x5c, + 0x03, 0xd5, 0x5b, 0x50, 0x4d, 0x88, 0x19, 0x95, 0x21, 0xdf, 0x3b, 0xea, 0x75, 0xb5, 0x35, 0x04, + 0x50, 0xec, 0xec, 0xe1, 0xa3, 0xa3, 0x81, 0xb8, 0x35, 0xec, 0x1f, 0xb6, 0x9f, 0x74, 0xb5, 0x9c, + 0xde, 0x85, 0x5a, 0x72, 0x41, 0x84, 0xa0, 0x7e, 0xd2, 0x7b, 0xda, 0x3b, 0x7a, 0xd6, 0x33, 0x0e, + 0x8f, 0x4e, 0x7a, 0x03, 0x76, 0xdf, 0xa8, 0x03, 0xb4, 0x7b, 0xcf, 0xa7, 0xf4, 0x3a, 0x54, 0x7a, + 0x47, 0x11, 0xa9, 0x34, 0x73, 0x9a, 0xa2, 0xff, 0xbb, 0x0a, 0x5b, 0x8b, 0x64, 0x8f, 0x2c, 0xc8, + 0x33, 0x3d, 0xca, 0x1b, 0xdf, 0xbb, 0x57, 0x23, 0x47, 0x67, 0xe6, 0xeb, 0x9b, 0xd2, 0xc5, 0x57, + 0x30, 0xff, 0x46, 0x06, 0x14, 0xc7, 0xe6, 0x29, 0x19, 0xd3, 0x86, 0xca, 0x73, 0x22, 0x4f, 0xae, + 0xb3, 0xf6, 0x01, 0x47, 0x12, 0x09, 0x11, 0x09, 0x8b, 0x06, 0x50, 0x65, 0x4e, 0x8c, 0x0a, 0xd1, + 0x49, 0xbf, 0xba, 0x93, 0x71, 0x95, 0xbd, 0xe9, 0x4c, 0x9c, 0x84, 0x69, 0x3e, 0x80, 0x6a, 0x62, + 0xb1, 0x05, 0xf9, 0x8c, 0xad, 0x64, 0x3e, 0xa3, 0x92, 0x4c, 0x4e, 0x3c, 0x9a, 0xd7, 0x01, 0x93, + 0x11, 0x33, 0x82, 0xbd, 0xa3, 0xfe, 0x40, 0xdc, 0x1c, 0x9f, 0xe0, 0xa3, 0x93, 0x63, 0x4d, 0x61, + 0x8d, 0x83, 0x76, 0xff, 0xa9, 0x96, 0x8b, 0x6d, 0x44, 0xd5, 0x3b, 0x50, 0x4d, 0xf0, 0x95, 0xf2, + 0xda, 0x4a, 0xda, 0x6b, 0x33, 0xbf, 0x69, 0x5a, 0x56, 0x40, 0x28, 0x95, 0x7c, 0x44, 0xa4, 0xfe, + 0x02, 0x2a, 0xbb, 0xbd, 0xbe, 0x84, 0x68, 0x40, 0x89, 0x92, 0x80, 0xfd, 0x6f, 0x9e, 0x99, 0xaa, + 0xe0, 0x88, 0x64, 0xe0, 0x94, 0x98, 0xc1, 0xf0, 0x8c, 0x50, 0x79, 0xd6, 0xc7, 0x34, 0x9b, 0xe5, + 0xf1, 0x0c, 0x8f, 0xd0, 0x5d, 0x05, 0x47, 0xa4, 0xfe, 0x3f, 0x25, 0x80, 0x69, 0xb6, 0x01, 0xd5, + 0x21, 0x17, 0xfb, 0xe0, 0x9c, 0x6d, 0x31, 0x3b, 0x48, 0x9c, 0x31, 0xfc, 0x1b, 0xed, 0xc0, 0x4d, + 0x87, 0x8e, 0x7c, 0x73, 0x78, 0x6e, 0xc8, 0x24, 0x81, 0xd8, 0xaa, 0xdc, 0x9f, 0xd5, 0xf0, 0x0d, + 0xd9, 0x29, 0x77, 0xa2, 0xc0, 0x3d, 0x00, 0x95, 0xb8, 0x17, 0xdc, 0xf7, 0x54, 0x77, 0x3e, 0x5b, + 0x3a, 0x0b, 0xd2, 0xea, 0xba, 0x17, 0xc2, 0x56, 0x18, 0x0c, 0x32, 0x00, 0x2c, 0x72, 0x61, 0x0f, + 0x89, 0xc1, 0x40, 0x0b, 0x1c, 0xf4, 0x8b, 0xe5, 0x41, 0x77, 0x39, 0x46, 0x0c, 0x5d, 0xb1, 0x22, + 0x1a, 0xf5, 0xa0, 0x12, 0x10, 0xea, 0x4d, 0x82, 0x21, 0x11, 0x0e, 0x28, 0xfb, 0x45, 0x05, 0x47, + 0xf3, 0xf0, 0x14, 0x02, 0xed, 0x42, 0x91, 0xfb, 0x1d, 0xe6, 0x61, 0xd4, 0xef, 0x4c, 0xa9, 0xa6, + 0xc1, 0xb8, 0x27, 0xc1, 0x72, 0x2e, 0x7a, 0x02, 0x25, 0xc1, 0x22, 0x6d, 0x94, 0x39, 0xcc, 0x47, + 0x59, 0x9d, 0x22, 0x9f, 0x85, 0xa3, 0xd9, 0x4c, 0xab, 0x13, 0x4a, 0x82, 0x46, 0x45, 0x68, 0x95, + 0x7d, 0xa3, 0xf7, 0xa0, 0x22, 0xce, 0x60, 0xcb, 0x0e, 0x1a, 0x20, 0x8c, 0x93, 0x37, 0xec, 0xda, + 0x01, 0x7a, 0x1f, 0xaa, 0x22, 0xd6, 0x32, 0xb8, 0x57, 0xa8, 0xf2, 0x6e, 0x10, 0x4d, 0xc7, 0xcc, + 0x37, 0x88, 0x01, 0x24, 0x08, 0xc4, 0x80, 0x5a, 0x3c, 0x80, 0x04, 0x01, 0x1f, 0xf0, 0x07, 0xb0, + 0xc1, 0x23, 0xd4, 0x51, 0xe0, 0x4d, 0x7c, 0x83, 0xdb, 0xd4, 0x3a, 0x1f, 0xb4, 0xce, 0x9a, 0x9f, + 0xb0, 0xd6, 0x1e, 0x33, 0xae, 0x3b, 0x50, 0x7e, 0xe5, 0x9d, 0x8a, 0x01, 0x75, 0xb1, 0x0f, 0x5e, + 0x79, 0xa7, 0x51, 0x57, 0x1c, 0x25, 0x6c, 0xa4, 0xa3, 0x84, 0x6f, 0xe0, 0xd6, 0xfc, 0x71, 0xc7, + 0xa3, 0x05, 0xed, 0xfa, 0xd1, 0xc2, 0x96, 0xbb, 0xc8, 0x0f, 0x7f, 0x09, 0xaa, 0xe5, 0xd2, 0xc6, + 0xe6, 0x52, 0xc6, 0x11, 0xef, 0x63, 0xcc, 0x26, 0x37, 0x3f, 0x81, 0x72, 0x64, 0x7d, 0xcb, 0xf8, + 0xa5, 0xe6, 0x43, 0xa8, 0xa7, 0x6d, 0x77, 0x29, 0xaf, 0xf6, 0xcf, 0x39, 0xa8, 0xc4, 0x56, 0x8a, + 0x5c, 0xb8, 0xc1, 0xa5, 0xc8, 0x42, 0x34, 0x63, 0x6a, 0xf4, 0x22, 0x30, 0xfc, 0x3c, 0xe3, 0xff, + 0x6a, 0x47, 0x08, 0xf2, 0x86, 0x2a, 0x77, 0x00, 0x8a, 0x91, 0xa7, 0xeb, 0x7d, 0x0d, 0x1b, 0x63, + 0xdb, 0x9d, 0x5c, 0x26, 0xd6, 0x12, 0x11, 0xdd, 0x1f, 0x66, 0x5c, 0xeb, 0x80, 0xcd, 0x9e, 0xae, + 0x51, 0x1f, 0xa7, 0x68, 0xb4, 0x07, 0x05, 0xdf, 0x0b, 0xc2, 0xe8, 0x90, 0xca, 0x7a, 0x7c, 0x1c, + 0x7b, 0x41, 0x78, 0x68, 0xfa, 0x3e, 0xbb, 0xb4, 0x08, 0x00, 0xfd, 0xdb, 0x1c, 0xdc, 0x5a, 0xfc, + 0xc7, 0x50, 0x0f, 0xd4, 0xa1, 0x3f, 0x91, 0x42, 0x7a, 0xb8, 0xac, 0x90, 0x3a, 0xfe, 0x64, 0xca, + 0x3f, 0x03, 0x42, 0xcf, 0xa0, 0xe8, 0x10, 0xc7, 0x0b, 0xae, 0xa4, 0x2c, 0x1e, 0x2d, 0x0b, 0x79, + 0xc8, 0x67, 0x4f, 0x51, 0x25, 0x1c, 0xc2, 0x50, 0x96, 0xd6, 0x4b, 0xa5, 0x9f, 0x5c, 0x32, 0xad, + 0x14, 0x41, 0xe2, 0x18, 0x47, 0xff, 0x04, 0x6e, 0x2e, 0xfc, 0x2b, 0xe8, 0x77, 0x01, 0x86, 0xfe, + 0xc4, 0xe0, 0x69, 0x7f, 0x61, 0x41, 0x2a, 0xae, 0x0c, 0xfd, 0x49, 0x9f, 0x37, 0xe8, 0x2f, 0xa0, + 0xf1, 0x26, 0x7e, 0x99, 0xf7, 0x11, 0x1c, 0x1b, 0xce, 0x29, 0x97, 0x81, 0x8a, 0xcb, 0xa2, 0xe1, + 0xf0, 0x14, 0xe9, 0xb0, 0x1e, 0x75, 0x9a, 0x97, 0x6c, 0x80, 0xca, 0x07, 0x54, 0xe5, 0x00, 0xf3, + 0xf2, 0xf0, 0x54, 0xff, 0x55, 0x0e, 0x36, 0x66, 0x58, 0x66, 0x57, 0x37, 0xe1, 0xf1, 0xa2, 0x4b, + 0xb1, 0xa0, 0x98, 0xfb, 0x1b, 0xda, 0x56, 0x94, 0x4e, 0xe5, 0xdf, 0xfc, 0xe0, 0xf3, 0x65, 0xaa, + 0x33, 0x67, 0xfb, 0x6c, 0xfb, 0x38, 0xa7, 0x76, 0x48, 0x79, 0x14, 0x52, 0xc0, 0x82, 0x40, 0xcf, + 0xa1, 0x1e, 0x10, 0x7e, 0xe0, 0x5a, 0x86, 0xb0, 0xb2, 0xc2, 0x52, 0x56, 0x26, 0x39, 0x64, 0xc6, + 0x86, 0xd7, 0x23, 0x24, 0x46, 0x51, 0xf4, 0x0c, 0xd6, 0xad, 0x2b, 0xd7, 0x74, 0xec, 0xa1, 0x44, + 0x2e, 0xae, 0x8c, 0x5c, 0x93, 0x40, 0x1c, 0x58, 0x7f, 0x00, 0xd5, 0x44, 0x27, 0xfb, 0x63, 0x3c, + 0xdc, 0x92, 0x32, 0x11, 0x44, 0xda, 0x5b, 0x14, 0xa4, 0xb7, 0xd0, 0x4f, 0xa1, 0x9a, 0xd8, 0x17, + 0xcb, 0x4c, 0x65, 0xf2, 0x0c, 0x3d, 0x2e, 0xcf, 0x02, 0xce, 0x85, 0x1e, 0xba, 0x0d, 0x25, 0x16, + 0xea, 0x18, 0xb6, 0xcf, 0x25, 0x5a, 0xc1, 0x45, 0x46, 0xee, 0xfb, 0xfa, 0x6f, 0x72, 0x50, 0x4f, + 0x6f, 0xe9, 0xc8, 0x8e, 0x7c, 0x12, 0xd8, 0x9e, 0x95, 0xb0, 0xa3, 0x63, 0xde, 0xc0, 0x6c, 0x85, + 0x75, 0x7f, 0x33, 0xf1, 0x42, 0x33, 0xb2, 0x95, 0xa1, 0x3f, 0xf9, 0x23, 0x46, 0xcf, 0xd8, 0xa0, + 0x3a, 0x63, 0x83, 0xe8, 0x43, 0x40, 0xd2, 0x94, 0xc6, 0xb6, 0x63, 0x87, 0xc6, 0xe9, 0x55, 0x48, + 0x84, 0x8e, 0x55, 0xac, 0x89, 0x9e, 0x03, 0xd6, 0xf1, 0x25, 0x6b, 0x67, 0x86, 0xe7, 0x79, 0x8e, + 0x41, 0x87, 0x5e, 0x40, 0x0c, 0xd3, 0x7a, 0xc5, 0x6f, 0x2d, 0x2a, 0xae, 0x7a, 0x9e, 0xd3, 0x67, + 0x6d, 0x6d, 0xeb, 0x15, 0x3b, 0xf9, 0x86, 0xfe, 0x84, 0x92, 0xd0, 0x60, 0x3f, 0x3c, 0x58, 0xa8, + 0x60, 0x10, 0x4d, 0x1d, 0x7f, 0x42, 0xd1, 0xef, 0xc3, 0x7a, 0x34, 0x80, 0x1f, 0x7e, 0xf2, 0xd4, + 0xad, 0xc9, 0x21, 0xbc, 0x0d, 0xe9, 0x50, 0x3b, 0x26, 0xc1, 0x90, 0xb8, 0xe1, 0xc0, 0x1e, 0x9e, + 0xb3, 0xf3, 0x5d, 0xd9, 0x56, 0x70, 0xaa, 0xed, 0xab, 0x7c, 0xb9, 0xa4, 0x95, 0x71, 0xb4, 0x9a, + 0x43, 0x1c, 0xaa, 0xff, 0x0c, 0x0a, 0x3c, 0x44, 0x60, 0x32, 0xe1, 0xc7, 0x2b, 0x3f, 0x7d, 0x65, + 0x68, 0xc9, 0x1a, 0xf8, 0xd9, 0xfb, 0x1e, 0x54, 0xb8, 0xec, 0x13, 0x11, 0x3d, 0x8f, 0x3b, 0x79, + 0x67, 0x13, 0xca, 0x01, 0x31, 0x2d, 0xcf, 0x1d, 0x47, 0xc9, 0xa0, 0x98, 0xd6, 0xbf, 0x81, 0xa2, + 0x38, 0x67, 0xae, 0x81, 0xff, 0x11, 0x20, 0xf1, 0xbf, 0x99, 0x3e, 0x1d, 0x9b, 0x52, 0x19, 0x85, + 0xf2, 0x17, 0x48, 0xd1, 0x73, 0x3c, 0xed, 0xd0, 0xff, 0x53, 0x11, 0xf1, 0xa8, 0x78, 0x1b, 0x62, + 0x81, 0x2b, 0x33, 0x72, 0x76, 0x5b, 0x16, 0x49, 0xa8, 0x88, 0x44, 0xfb, 0x50, 0x94, 0x61, 0x67, + 0x6e, 0xd5, 0xa7, 0x35, 0x09, 0x10, 0xa5, 0xa4, 0x89, 0xbc, 0x90, 0x2f, 0x9b, 0x92, 0x26, 0x22, + 0x25, 0x4d, 0xd8, 0x6d, 0x52, 0x06, 0xc4, 0x02, 0x2e, 0xcf, 0xe3, 0xe1, 0xaa, 0x15, 0xe7, 0xfd, + 0x89, 0xfe, 0xdf, 0x4a, 0xec, 0xa6, 0xa2, 0xfc, 0x3c, 0xfa, 0x1a, 0xca, 0x6c, 0xc7, 0x1b, 0x8e, + 0xe9, 0xcb, 0xd7, 0xe6, 0xce, 0x6a, 0xa9, 0xff, 0xe8, 0x10, 0x13, 0xe1, 0x6c, 0xc9, 0x17, 0x14, + 0x73, 0x77, 0xec, 0x2a, 0x11, 0xb9, 0x3b, 0xf6, 0x8d, 0x3e, 0x80, 0xba, 0x39, 0x09, 0x3d, 0xc3, + 0xb4, 0x2e, 0x48, 0x10, 0xda, 0x94, 0x48, 0xdd, 0xaf, 0xb3, 0xd6, 0x76, 0xd4, 0xd8, 0xfc, 0x0c, + 0x6a, 0x49, 0xcc, 0xb7, 0x85, 0x19, 0x85, 0x64, 0x98, 0xf1, 0xa7, 0x00, 0xd3, 0x5c, 0x17, 0xb3, + 0x11, 0x72, 0x69, 0xb3, 0x5b, 0xbd, 0xbc, 0xbb, 0x16, 0x70, 0x99, 0x35, 0x74, 0xd8, 0x7d, 0x2a, + 0x9d, 0x88, 0x2f, 0x44, 0x89, 0x78, 0xb6, 0x99, 0xd9, 0xfe, 0x3b, 0xb7, 0xc7, 0xe3, 0x38, 0xff, + 0x56, 0xf1, 0x3c, 0xe7, 0x29, 0x6f, 0xd0, 0x7f, 0x9b, 0x13, 0xb6, 0x22, 0x9e, 0x54, 0x32, 0xdd, + 0x5d, 0xde, 0x95, 0xaa, 0x1f, 0x00, 0xd0, 0xd0, 0x0c, 0x58, 0xcc, 0x64, 0x46, 0x19, 0xc0, 0xe6, + 0x5c, 0x26, 0x7f, 0x10, 0xd5, 0x78, 0xe0, 0x8a, 0x1c, 0xdd, 0x0e, 0xd1, 0xe7, 0x50, 0x1b, 0x7a, + 0x8e, 0x3f, 0x26, 0x72, 0x72, 0xe1, 0xad, 0x93, 0xab, 0xf1, 0xf8, 0x76, 0x98, 0xc8, 0x3b, 0x16, + 0xaf, 0x9b, 0x77, 0xfc, 0x8d, 0x22, 0x5e, 0x86, 0x92, 0x0f, 0x53, 0x68, 0xb4, 0xa0, 0xfa, 0xe1, + 0xc9, 0x8a, 0xaf, 0x5c, 0xdf, 0x55, 0xfa, 0xd0, 0xfc, 0x3c, 0x4b, 0xad, 0xc1, 0x9b, 0xa3, 0xd8, + 0x7f, 0x53, 0xa1, 0x12, 0x3f, 0x0a, 0xcd, 0xe9, 0xfe, 0x53, 0xa8, 0xc4, 0x05, 0x36, 0xd2, 0x41, + 0x7c, 0xa7, 0x7a, 0xe2, 0xc1, 0xe8, 0x25, 0x20, 0x73, 0x34, 0x8a, 0xa3, 0x53, 0x63, 0x42, 0xcd, + 0x51, 0xf4, 0x24, 0xf7, 0xe9, 0x12, 0x72, 0x88, 0x8e, 0xb3, 0x13, 0x36, 0x1f, 0x6b, 0xe6, 0x68, + 0x94, 0x6a, 0x41, 0x7f, 0x06, 0x37, 0xd3, 0x6b, 0x18, 0xa7, 0x57, 0x86, 0x6f, 0x5b, 0xf2, 0x8e, + 0xbc, 0xb7, 0xec, 0xbb, 0x58, 0x2b, 0x05, 0xff, 0xe5, 0xd5, 0xb1, 0x6d, 0x09, 0x99, 0xa3, 0x60, + 0xae, 0xa3, 0xf9, 0x17, 0x70, 0xfb, 0x0d, 0xc3, 0x17, 0xe8, 0xa0, 0x97, 0xae, 0xf7, 0x58, 0x5d, + 0x08, 0x09, 0xed, 0xfd, 0x5a, 0x11, 0xcf, 0x77, 0x69, 0x99, 0xb4, 0x93, 0x61, 0xf5, 0xbd, 0x8c, + 0xeb, 0x74, 0x8e, 0x4f, 0x04, 0x3c, 0x8f, 0xa4, 0xbf, 0x9a, 0x89, 0xa4, 0xb3, 0xc6, 0x4f, 0x22, + 0x20, 0x15, 0x40, 0x12, 0x41, 0xff, 0x17, 0x15, 0xca, 0x11, 0x3a, 0xbf, 0xe1, 0x5e, 0xd1, 0x90, + 0x38, 0x46, 0x9c, 0x7e, 0x53, 0x30, 0x88, 0x26, 0x9e, 0x14, 0x7a, 0x0f, 0x2a, 0xec, 0x22, 0x2d, + 0xba, 0x73, 0xbc, 0xbb, 0xcc, 0x1a, 0x78, 0xe7, 0xfb, 0x50, 0x0d, 0xbd, 0xd0, 0x1c, 0x1b, 0x21, + 0x3f, 0xde, 0x55, 0x31, 0x9b, 0x37, 0xf1, 0xc3, 0x1d, 0xfd, 0x00, 0x36, 0xc3, 0xb3, 0xc0, 0x0b, + 0xc3, 0x31, 0x0b, 0x2d, 0x79, 0xa0, 0x23, 0xe2, 0x92, 0x3c, 0xd6, 0xe2, 0x0e, 0x11, 0x00, 0x51, + 0xe6, 0xbd, 0xa7, 0x83, 0x99, 0xe9, 0x72, 0x27, 0x92, 0xc7, 0xeb, 0x71, 0x2b, 0x33, 0x6d, 0x76, + 0x78, 0xfa, 0x22, 0x80, 0xe0, 0xbe, 0x42, 0xc1, 0x11, 0x89, 0x0c, 0xd8, 0x70, 0x88, 0x49, 0x27, + 0x01, 0xb1, 0x8c, 0x97, 0x36, 0x19, 0x5b, 0x22, 0x31, 0x51, 0xcf, 0x7c, 0x3b, 0x88, 0xc4, 0xd2, + 0x7a, 0xcc, 0x67, 0xe3, 0x7a, 0x04, 0x27, 0x68, 0x16, 0x39, 0x88, 0x2f, 0xb4, 0x01, 0xd5, 0xfe, + 0xf3, 0xfe, 0xa0, 0x7b, 0x68, 0x1c, 0x1e, 0xed, 0x76, 0x65, 0x49, 0x4f, 0xbf, 0x8b, 0x05, 0xa9, + 0xb0, 0xfe, 0xc1, 0xd1, 0xa0, 0x7d, 0x60, 0x0c, 0xf6, 0x3b, 0x4f, 0xfb, 0x5a, 0x0e, 0xdd, 0x84, + 0xcd, 0xc1, 0x1e, 0x3e, 0x1a, 0x0c, 0x0e, 0xba, 0xbb, 0xc6, 0x71, 0x17, 0xef, 0x1f, 0xed, 0xf6, + 0x35, 0x15, 0x21, 0xa8, 0x4f, 0x9b, 0x07, 0xfb, 0x87, 0x5d, 0x2d, 0x8f, 0xaa, 0x50, 0x3a, 0xee, + 0xe2, 0x4e, 0xb7, 0x37, 0xd0, 0x0a, 0xfa, 0xaf, 0x54, 0xa8, 0x26, 0xb4, 0xc8, 0x0c, 0x39, 0xa0, + 0xe2, 0x1a, 0x92, 0xc7, 0xec, 0x93, 0x3f, 0x41, 0x9a, 0xc3, 0x33, 0xa1, 0x9d, 0x3c, 0x16, 0x04, + 0xbf, 0x7a, 0x98, 0x97, 0x89, 0x7d, 0x9e, 0xc7, 0x65, 0xc7, 0xbc, 0x14, 0x20, 0xdf, 0x83, 0xda, + 0x39, 0x09, 0x5c, 0x32, 0x96, 0xfd, 0x42, 0x23, 0x55, 0xd1, 0x26, 0x86, 0x6c, 0x83, 0x26, 0x87, + 0x4c, 0x61, 0x84, 0x3a, 0xea, 0xa2, 0xfd, 0x30, 0x02, 0xdb, 0x82, 0x82, 0xe8, 0x2e, 0x89, 0xf5, + 0x39, 0xc1, 0x8e, 0x29, 0xfa, 0xda, 0xf4, 0x79, 0xc8, 0x97, 0xc7, 0xfc, 0x1b, 0x9d, 0xce, 0xeb, + 0xa7, 0xc8, 0xf5, 0xf3, 0x60, 0x79, 0x73, 0x7e, 0x93, 0x8a, 0xce, 0x62, 0x15, 0x95, 0x40, 0xc5, + 0x51, 0x1d, 0x4c, 0xa7, 0xdd, 0xd9, 0x63, 0x6a, 0x59, 0x87, 0xca, 0x61, 0xfb, 0xa7, 0xc6, 0x49, + 0x9f, 0x67, 0xb5, 0x91, 0x06, 0xb5, 0xa7, 0x5d, 0xdc, 0xeb, 0x1e, 0xc8, 0x16, 0x15, 0x6d, 0x81, + 0x26, 0x5b, 0xa6, 0xe3, 0xf2, 0x0c, 0x41, 0x7c, 0x16, 0x50, 0x19, 0xf2, 0xfd, 0x67, 0xed, 0x63, + 0xad, 0xa8, 0xff, 0x57, 0x0e, 0x36, 0xc4, 0xb1, 0x10, 0xbf, 0xd8, 0xbf, 0xf9, 0xc5, 0x32, 0x99, + 0xe5, 0xc9, 0xa5, 0xb3, 0x3c, 0x51, 0x10, 0xca, 0x4f, 0x75, 0x75, 0x1a, 0x84, 0xf2, 0xec, 0x50, + 0xca, 0xe3, 0xe7, 0x97, 0xf1, 0xf8, 0x0d, 0x28, 0x39, 0x84, 0xc6, 0x7a, 0xab, 0xe0, 0x88, 0x44, + 0x36, 0x54, 0x4d, 0xd7, 0xf5, 0x42, 0x53, 0xa4, 0x4e, 0x8b, 0x4b, 0x1d, 0x86, 0x33, 0xff, 0xb8, + 0xd5, 0x9e, 0x22, 0x09, 0xc7, 0x9c, 0xc4, 0x6e, 0xfe, 0x04, 0xb4, 0xd9, 0x01, 0xcb, 0x1c, 0x87, + 0xdf, 0xff, 0xe1, 0xf4, 0x34, 0x24, 0x6c, 0x5f, 0xc8, 0x37, 0x07, 0x6d, 0x8d, 0x11, 0xf8, 0xa4, + 0xd7, 0xdb, 0xef, 0x3d, 0xd1, 0x14, 0x04, 0x50, 0xec, 0xfe, 0x74, 0x7f, 0xd0, 0xdd, 0xd5, 0x72, + 0x3b, 0xbf, 0xde, 0x84, 0xa2, 0x60, 0x12, 0x7d, 0x2b, 0x23, 0x81, 0x64, 0x35, 0x28, 0xfa, 0xc9, + 0xd2, 0x11, 0x75, 0xaa, 0xc2, 0xb4, 0xf9, 0x68, 0xe5, 0xf9, 0xf2, 0xf5, 0x6d, 0x0d, 0xfd, 0x8d, + 0x02, 0xb5, 0xd4, 0xcb, 0x5b, 0xd6, 0xd4, 0xf1, 0x82, 0xe2, 0xd3, 0xe6, 0x8f, 0x57, 0x9a, 0x1b, + 0xf3, 0xf2, 0x4b, 0x05, 0xaa, 0x89, 0xb2, 0x4b, 0xf4, 0x60, 0x95, 0x52, 0x4d, 0xc1, 0xc9, 0x67, + 0xab, 0x57, 0x79, 0xea, 0x6b, 0x1f, 0x2b, 0xe8, 0xaf, 0x15, 0xa8, 0x26, 0x0a, 0x10, 0x33, 0xb3, + 0x32, 0x5f, 0x2e, 0x99, 0x99, 0x95, 0x45, 0xf5, 0x8e, 0x6b, 0xe8, 0x2f, 0x15, 0xa8, 0xc4, 0xc5, + 0x84, 0xe8, 0xfe, 0xf2, 0xe5, 0x87, 0x82, 0x89, 0x4f, 0x57, 0xad, 0x5b, 0xd4, 0xd7, 0xd0, 0x9f, + 0x43, 0x39, 0xaa, 0xbc, 0x43, 0x59, 0x4f, 0xaf, 0x99, 0xb2, 0xbe, 0xe6, 0xfd, 0xa5, 0xe7, 0x25, + 0x97, 0x8f, 0xca, 0xe1, 0x32, 0x2f, 0x3f, 0x53, 0xb8, 0xd7, 0xbc, 0xbf, 0xf4, 0xbc, 0x78, 0x79, + 0x66, 0x09, 0x89, 0xaa, 0xb9, 0xcc, 0x96, 0x30, 0x5f, 0xae, 0x97, 0xd9, 0x12, 0x16, 0x15, 0xe9, + 0x09, 0x46, 0x12, 0x75, 0x77, 0x99, 0x19, 0x99, 0xaf, 0xed, 0xcb, 0xcc, 0xc8, 0x82, 0x32, 0x3f, + 0x7d, 0x0d, 0xfd, 0x42, 0x49, 0xde, 0x0b, 0xee, 0x2f, 0x5d, 0x5e, 0xb6, 0xa4, 0x49, 0xce, 0x15, + 0xb8, 0xf1, 0x0d, 0xfa, 0x0b, 0x99, 0xc5, 0x10, 0xd5, 0x69, 0x68, 0x19, 0xb0, 0x54, 0x41, 0x5b, + 0xf3, 0x93, 0xd5, 0x0e, 0x1b, 0xce, 0xc4, 0x5f, 0x29, 0x00, 0xd3, 0x3a, 0xb6, 0xcc, 0x4c, 0xcc, + 0x15, 0xd0, 0x35, 0x1f, 0xac, 0x30, 0x33, 0xb9, 0x41, 0xa2, 0x3a, 0x9b, 0xcc, 0x1b, 0x64, 0xa6, + 0xce, 0x2e, 0xf3, 0x06, 0x99, 0xad, 0x91, 0xd3, 0xd7, 0xd0, 0x3f, 0x29, 0xb0, 0x39, 0x57, 0xe7, + 0x83, 0x1e, 0x5d, 0xb3, 0xd4, 0xab, 0xf9, 0xc5, 0xea, 0x00, 0x11, 0x6b, 0xdb, 0xca, 0xc7, 0x0a, + 0xfa, 0x5b, 0x05, 0xd6, 0xd3, 0xf5, 0x0f, 0x99, 0x4f, 0xa9, 0x05, 0x15, 0x43, 0xcd, 0x87, 0xab, + 0x4d, 0x8e, 0xa5, 0xf5, 0xf7, 0x0a, 0xd4, 0xd3, 0xa5, 0x30, 0xe8, 0xe1, 0x72, 0x6e, 0x61, 0x86, + 0xa1, 0xcf, 0x57, 0x9c, 0x1d, 0x71, 0xf4, 0x65, 0xe9, 0x8f, 0x0b, 0x22, 0x7a, 0x2b, 0xf2, 0x9f, + 0x1f, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x76, 0x8b, 0xb6, 0x52, 0xb4, 0x33, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/plugins/drivers/proto/driver.proto b/plugins/drivers/proto/driver.proto index dc4b2f061460..f315d3215dbd 100644 --- a/plugins/drivers/proto/driver.proto +++ b/plugins/drivers/proto/driver.proto @@ -329,6 +329,9 @@ message CreateNetworkRequest { // AllocID of the allocation the network is associated with string alloc_id = 1; + + // Hostname of the network namespace + string hostname = 2; } message CreateNetworkResponse { diff --git a/plugins/drivers/server.go b/plugins/drivers/server.go index f79690e444a0..15896801e645 100644 --- a/plugins/drivers/server.go +++ b/plugins/drivers/server.go @@ -388,7 +388,7 @@ func (b *driverPluginServer) CreateNetwork(ctx context.Context, req *proto.Creat return nil, fmt.Errorf("CreateNetwork RPC not supported by driver") } - spec, created, err := nm.CreateNetwork(req.AllocId) + spec, created, err := nm.CreateNetwork(req.GetAllocId(), networkCreateRequestFromProto(req)) if err != nil { return nil, err } @@ -397,7 +397,6 @@ func (b *driverPluginServer) CreateNetwork(ctx context.Context, req *proto.Creat IsolationSpec: NetworkIsolationSpecToProto(spec), Created: created, }, nil - } func (b *driverPluginServer) DestroyNetwork(ctx context.Context, req *proto.DestroyNetworkRequest) (*proto.DestroyNetworkResponse, error) { diff --git a/plugins/drivers/testutils/testing.go b/plugins/drivers/testutils/testing.go index 8e2ea66799a6..8088381db6c9 100644 --- a/plugins/drivers/testutils/testing.go +++ b/plugins/drivers/testutils/testing.go @@ -199,12 +199,12 @@ type MockDriver struct { } type MockNetworkManager struct { - CreateNetworkF func(string) (*drivers.NetworkIsolationSpec, bool, error) + CreateNetworkF func(string, *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error) DestroyNetworkF func(string, *drivers.NetworkIsolationSpec) error } -func (m *MockNetworkManager) CreateNetwork(id string) (*drivers.NetworkIsolationSpec, bool, error) { - return m.CreateNetworkF(id) +func (m *MockNetworkManager) CreateNetwork(allocID string, req *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error) { + return m.CreateNetworkF(allocID, req) } func (m *MockNetworkManager) DestroyNetwork(id string, spec *drivers.NetworkIsolationSpec) error { return m.DestroyNetworkF(id, spec) diff --git a/plugins/drivers/utils.go b/plugins/drivers/utils.go index 9b1f4988f60f..7639ef4c32cd 100644 --- a/plugins/drivers/utils.go +++ b/plugins/drivers/utils.go @@ -635,6 +635,15 @@ func netIsolationModeFromProto(pb proto.NetworkIsolationSpec_NetworkIsolationMod } } +func networkCreateRequestFromProto(pb *proto.CreateNetworkRequest) *NetworkCreateRequest { + if pb == nil { + return nil + } + return &NetworkCreateRequest{ + Hostname: pb.GetHostname(), + } +} + func NetworkIsolationSpecToProto(spec *NetworkIsolationSpec) *proto.NetworkIsolationSpec { if spec == nil { return nil diff --git a/plugins/drivers/utils_test.go b/plugins/drivers/utils_test.go index 5f46dc8a1978..f12cac479fce 100644 --- a/plugins/drivers/utils_test.go +++ b/plugins/drivers/utils_test.go @@ -5,6 +5,8 @@ import ( "github.com/hashicorp/nomad/helper/uuid" "github.com/hashicorp/nomad/nomad/structs" + "github.com/hashicorp/nomad/plugins/drivers/proto" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -103,3 +105,34 @@ func TestTaskConfigRoundTrip(t *testing.T) { require.EqualValues(t, input, parsed) } + +func Test_networkCreateRequestFromProto(t *testing.T) { + testCases := []struct { + inputPB *proto.CreateNetworkRequest + expectedOutput *NetworkCreateRequest + name string + }{ + { + inputPB: nil, + expectedOutput: nil, + name: "nil safety", + }, + { + inputPB: &proto.CreateNetworkRequest{ + AllocId: "59598b74-86e9-16ee-eb54-24c62935cc7c", + Hostname: "foobar", + }, + expectedOutput: &NetworkCreateRequest{ + Hostname: "foobar", + }, + name: "generic 1", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actualOutput := networkCreateRequestFromProto(tc.inputPB) + assert.Equal(t, tc.expectedOutput, actualOutput, tc.name) + }) + } +} diff --git a/scheduler/util.go b/scheduler/util.go index 865803720bae..9996f69e7c61 100644 --- a/scheduler/util.go +++ b/scheduler/util.go @@ -538,6 +538,10 @@ func networkUpdated(netA, netB []*structs.NetworkResource) bool { return true } + if an.Hostname != bn.Hostname { + return true + } + if !reflect.DeepEqual(an.DNS, bn.DNS) { return true } diff --git a/scheduler/util_test.go b/scheduler/util_test.go index d0e3c6520063..1d589fa24e79 100644 --- a/scheduler/util_test.go +++ b/scheduler/util_test.go @@ -809,6 +809,16 @@ func TestNetworkUpdated(t *testing.T) { }, updated: true, }, + { + name: "hostname updated", + a: []*structs.NetworkResource{ + {Hostname: "foo"}, + }, + b: []*structs.NetworkResource{ + {Hostname: "bar"}, + }, + updated: true, + }, } for i := range cases {