From e97671f293f4fe01139506c8d50139c55b7f1dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nils=20m=C3=A5s=C3=A9n?= Date: Tue, 8 Aug 2023 18:04:34 +0200 Subject: [PATCH] add additional test and further rework client mocks --- pkg/container/client.go | 14 +- pkg/container/client_test.go | 49 +++-- pkg/container/mocks/ApiServer.go | 141 ++++++++---- pkg/container/mocks/container_ref.go | 42 ++++ ...ntainer_net_consumer-missing_supplier.json | 205 ++++++++++++++++++ ...ducer.json => container_net_supplier.json} | 0 6 files changed, 384 insertions(+), 67 deletions(-) create mode 100644 pkg/container/mocks/container_ref.go create mode 100644 pkg/container/mocks/data/container_net_consumer-missing_supplier.json rename pkg/container/mocks/data/{container_net_producer.json => container_net_supplier.json} (100%) diff --git a/pkg/container/client.go b/pkg/container/client.go index 0e256bc..0d6c88d 100644 --- a/pkg/container/client.go +++ b/pkg/container/client.go @@ -157,12 +157,18 @@ func (client dockerClient) GetContainer(containerID t.ContainerID) (t.Container, return &Container{}, err } - containerNetworkMode := strings.Split(string(containerInfo.HostConfig.NetworkMode), ":") - if len(containerNetworkMode) == 2 && containerNetworkMode[0] == "container" { - parentContainer, err := client.api.ContainerInspect(bg, containerNetworkMode[1]) + netType, netContainerId, found := strings.Cut(string(containerInfo.HostConfig.NetworkMode), ":") + if found && netType == "container" { + parentContainer, err := client.api.ContainerInspect(bg, netContainerId) if err != nil { - log.Debug("Unable to fetch parentContainer.") + log.WithFields(map[string]interface{}{ + "container": containerInfo.Name, + "error": err, + "network-container": netContainerId, + }).Warnf("Unable to resolve network container: %v", err) + } else { + // Replace the container ID with a container name to allow it to reference the re-created network container containerInfo.HostConfig.NetworkMode = container.NetworkMode(fmt.Sprintf("container:%s", parentContainer.Name)) } } diff --git a/pkg/container/client_test.go b/pkg/container/client_test.go index 02482fa..789cf39 100644 --- a/pkg/container/client_test.go +++ b/pkg/container/client_test.go @@ -140,7 +140,7 @@ var _ = Describe("the client", func() { When("no filter is provided", func() { It("should return all available containers", func() { mockServer.AppendHandlers(mocks.ListContainersHandler("running")) - mockServer.AppendHandlers(mocks.GetContainerHandlers("watchtower", "running")...) + mockServer.AppendHandlers(mocks.GetContainerHandlers(&mocks.Watchtower, &mocks.Running)...) client := dockerClient{ api: docker, ClientOptions: ClientOptions{PullImages: false}, @@ -153,7 +153,7 @@ var _ = Describe("the client", func() { When("a filter matching nothing", func() { It("should return an empty array", func() { mockServer.AppendHandlers(mocks.ListContainersHandler("running")) - mockServer.AppendHandlers(mocks.GetContainerHandlers("watchtower", "running")...) + mockServer.AppendHandlers(mocks.GetContainerHandlers(&mocks.Watchtower, &mocks.Running)...) filter := filters.FilterByNames([]string{"lollercoaster"}, filters.NoFilter) client := dockerClient{ api: docker, @@ -167,7 +167,7 @@ var _ = Describe("the client", func() { When("a watchtower filter is provided", func() { It("should return only the watchtower container", func() { mockServer.AppendHandlers(mocks.ListContainersHandler("running")) - mockServer.AppendHandlers(mocks.GetContainerHandlers("watchtower", "running")...) + mockServer.AppendHandlers(mocks.GetContainerHandlers(&mocks.Watchtower, &mocks.Running)...) client := dockerClient{ api: docker, ClientOptions: ClientOptions{PullImages: false}, @@ -180,7 +180,7 @@ var _ = Describe("the client", func() { When(`include stopped is enabled`, func() { It("should return both stopped and running containers", func() { mockServer.AppendHandlers(mocks.ListContainersHandler("running", "exited", "created")) - mockServer.AppendHandlers(mocks.GetContainerHandlers("stopped", "watchtower", "running")...) + mockServer.AppendHandlers(mocks.GetContainerHandlers(&mocks.Stopped, &mocks.Watchtower, &mocks.Running)...) client := dockerClient{ api: docker, ClientOptions: ClientOptions{PullImages: false, IncludeStopped: true}, @@ -193,7 +193,7 @@ var _ = Describe("the client", func() { When(`include restarting is enabled`, func() { It("should return both restarting and running containers", func() { mockServer.AppendHandlers(mocks.ListContainersHandler("running", "restarting")) - mockServer.AppendHandlers(mocks.GetContainerHandlers("watchtower", "running", "restarting")...) + mockServer.AppendHandlers(mocks.GetContainerHandlers(&mocks.Watchtower, &mocks.Running, &mocks.Restarting)...) client := dockerClient{ api: docker, ClientOptions: ClientOptions{PullImages: false, IncludeRestarting: true}, @@ -206,7 +206,7 @@ var _ = Describe("the client", func() { When(`include restarting is disabled`, func() { It("should not return restarting containers", func() { mockServer.AppendHandlers(mocks.ListContainersHandler("running")) - mockServer.AppendHandlers(mocks.GetContainerHandlers("watchtower", "running")...) + mockServer.AppendHandlers(mocks.GetContainerHandlers(&mocks.Watchtower, &mocks.Running)...) client := dockerClient{ api: docker, ClientOptions: ClientOptions{PullImages: false, IncludeRestarting: false}, @@ -217,16 +217,33 @@ var _ = Describe("the client", func() { }) }) When(`a container uses container network mode`, func() { - It("should return the container name instead of the ID", func() { - mockServer.AppendHandlers(mocks.GetContainerHandlers("net_consumer")...) - client := dockerClient{ - api: docker, - ClientOptions: ClientOptions{PullImages: false}, - } - container, err := client.GetContainer(mocks.NetConsumerID) - Expect(err).NotTo(HaveOccurred()) - networkMode := container.ContainerInfo().HostConfig.NetworkMode - Expect(networkMode.ConnectedContainer()).To(Equal(mocks.NetProducerContainerName)) + When(`the network container can be resolved`, func() { + It("should return the container name instead of the ID", func() { + consumerContainerRef := mocks.NetConsumerOK + mockServer.AppendHandlers(mocks.GetContainerHandlers(&consumerContainerRef)...) + client := dockerClient{ + api: docker, + ClientOptions: ClientOptions{PullImages: false}, + } + container, err := client.GetContainer(consumerContainerRef.ContainerID()) + Expect(err).NotTo(HaveOccurred()) + networkMode := container.ContainerInfo().HostConfig.NetworkMode + Expect(networkMode.ConnectedContainer()).To(Equal(mocks.NetSupplierContainerName)) + }) + }) + When(`the network container cannot be resolved`, func() { + It("should still return the container ID", func() { + consumerContainerRef := mocks.NetConsumerInvalidSupplier + mockServer.AppendHandlers(mocks.GetContainerHandlers(&consumerContainerRef)...) + client := dockerClient{ + api: docker, + ClientOptions: ClientOptions{PullImages: false}, + } + container, err := client.GetContainer(consumerContainerRef.ContainerID()) + Expect(err).NotTo(HaveOccurred()) + networkMode := container.ContainerInfo().HostConfig.NetworkMode + Expect(networkMode.ConnectedContainer()).To(Equal(mocks.NetSupplierNotFoundID)) + }) }) }) }) diff --git a/pkg/container/mocks/ApiServer.go b/pkg/container/mocks/ApiServer.go index 1eeb8b2..84756f0 100644 --- a/pkg/container/mocks/ApiServer.go +++ b/pkg/container/mocks/ApiServer.go @@ -3,9 +3,10 @@ package mocks import ( "encoding/json" "fmt" - "io/ioutil" + "github.com/onsi/ginkgo" "net/http" "net/url" + "os" "path/filepath" "strings" @@ -19,10 +20,9 @@ import ( func getMockJSONFile(relPath string) ([]byte, error) { absPath, _ := filepath.Abs(relPath) - buf, err := ioutil.ReadFile(absPath) + buf, err := os.ReadFile(absPath) if err != nil { - // logrus.WithError(err).WithField("file", absPath).Error(err) - return nil, err + return nil, fmt.Errorf("mock JSON file %q not found: %e", absPath, err) } return buf, nil } @@ -43,19 +43,22 @@ func respondWithJSONFile(relPath string, statusCode int, optionalHeader ...http. } // GetContainerHandlers returns the handlers serving lookups for the supplied container mock files -func GetContainerHandlers(containerFiles ...string) []http.HandlerFunc { - handlers := make([]http.HandlerFunc, 0, len(containerFiles)*2) - for _, file := range containerFiles { - handlers = append(handlers, getContainerFileHandler(file)) +func GetContainerHandlers(containerRefs ...*ContainerRef) []http.HandlerFunc { + handlers := make([]http.HandlerFunc, 0, len(containerRefs)*3) + for _, containerRef := range containerRefs { + handlers = append(handlers, getContainerFileHandler(containerRef)) - if file == "net_consumer" { - // Also append the net_producer container, since it's used to reconfigure networking - handlers = append(handlers, getContainerFileHandler("net_producer")) + // Also append any containers that the container references, if any + for _, ref := range containerRef.references { + handlers = append(handlers, getContainerFileHandler(ref)) } // Also append the image request since that will be called for every container - handlers = append(handlers, getImageFileHandler(file)) + handlers = append(handlers, getImageHandler(containerRef.image.id, + RespondWithJSONFile(containerRef.image.getFileName(), http.StatusOK), + )) } + return handlers } @@ -67,32 +70,90 @@ func createFilterArgs(statuses []string) filters.Args { return args } -const NetConsumerID = "1f6b79d2aff23244382026c76f4995851322bed5f9c50631620162f6f9aafbd6" -const NetProducerID = "25e75393800b5c450a6841212a3b92ed28fa35414a586dec9f2c8a520d4910c2" -const NetProducerContainerName = "/wt-contnet-producer-1" - -var containerFileIds = map[string]string{ - "stopped": "ae8964ba86c7cd7522cf84e09781343d88e0e3543281c747d88b27e246578b65", - "watchtower": "3d88e0e3543281c747d88b27e246578b65ae8964ba86c7cd7522cf84e0978134", - "running": "b978af0b858aa8855cce46b628817d4ed58e58f2c4f66c9b9c5449134ed4c008", - "restarting": "ae8964ba86c7cd7522cf84e09781343d88e0e3543281c747d88b27e246578b67", - "net_consumer": NetConsumerID, - "net_producer": NetProducerID, +var defaultImage = imageRef{ + // watchtower + id: t.ImageID("sha256:4dbc5f9c07028a985e14d1393e849ea07f68804c4293050d5a641b138db72daa"), + file: "default", } -var imageIds = map[string]t.ImageID{ - "default": t.ImageID("sha256:4dbc5f9c07028a985e14d1393e849ea07f68804c4293050d5a641b138db72daa"), // watchtower - "running": t.ImageID("sha256:19d07168491a3f9e2798a9bed96544e34d57ddc4757a4ac5bb199dea896c87fd"), // portainer - "net_consumer": t.ImageID("sha256:904b8cb13b932e23230836850610fa45dce9eb0650d5618c2b1487c2a4f577b8"), // nginx - "net_producer": t.ImageID("sha256:c22b543d33bfdcb9992cbef23961677133cdf09da71d782468ae2517138bad51"), // gluetun +var Watchtower = ContainerRef{ + name: "watchtower", + id: "3d88e0e3543281c747d88b27e246578b65ae8964ba86c7cd7522cf84e0978134", + image: &defaultImage, +} +var Stopped = ContainerRef{ + name: "stopped", + id: "ae8964ba86c7cd7522cf84e09781343d88e0e3543281c747d88b27e246578b65", + image: &defaultImage, +} +var Running = ContainerRef{ + name: "running", + id: "b978af0b858aa8855cce46b628817d4ed58e58f2c4f66c9b9c5449134ed4c008", + image: &imageRef{ + // portainer + id: t.ImageID("sha256:19d07168491a3f9e2798a9bed96544e34d57ddc4757a4ac5bb199dea896c87fd"), + file: "running", + }, +} +var Restarting = ContainerRef{ + name: "restarting", + id: "ae8964ba86c7cd7522cf84e09781343d88e0e3543281c747d88b27e246578b67", + image: &defaultImage, } -func getContainerFileHandler(file string) http.HandlerFunc { - id, ok := containerFileIds[file] - failTestUnless(ok) +var netSupplierOK = ContainerRef{ + id: "25e75393800b5c450a6841212a3b92ed28fa35414a586dec9f2c8a520d4910c2", + name: "net_supplier", + image: &imageRef{ + // gluetun + id: t.ImageID("sha256:c22b543d33bfdcb9992cbef23961677133cdf09da71d782468ae2517138bad51"), + file: "net_producer", + }, +} +var netSupplierNotFound = ContainerRef{ + id: NetSupplierNotFoundID, + name: netSupplierOK.name, + isMissing: true, +} + +// NetConsumerOK is used for testing `container` networking mode +// returns a container that consumes an existing supplier container +var NetConsumerOK = ContainerRef{ + id: "1f6b79d2aff23244382026c76f4995851322bed5f9c50631620162f6f9aafbd6", + name: "net_consumer", + image: &imageRef{ + id: t.ImageID("sha256:904b8cb13b932e23230836850610fa45dce9eb0650d5618c2b1487c2a4f577b8"), // nginx + file: "net_consumer", + }, + references: []*ContainerRef{&netSupplierOK}, +} + +// NetConsumerInvalidSupplier is used for testing `container` networking mode +// returns a container that references a supplying container that does not exist +var NetConsumerInvalidSupplier = ContainerRef{ + id: NetConsumerOK.id, + name: "net_consumer-missing_supplier", + image: NetConsumerOK.image, + references: []*ContainerRef{&netSupplierNotFound}, +} + +const NetSupplierNotFoundID = "badc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc" +const NetSupplierContainerName = "/wt-contnet-producer-1" + +func getContainerFileHandler(cr *ContainerRef) http.HandlerFunc { + + if cr.isMissing { + return containerNotFoundResponse(string(cr.id)) + } + + containerFile, err := cr.getContainerFile() + if err != nil { + ginkgo.Fail(fmt.Sprintf("Failed to get container mock file: %v", err)) + } + return getContainerHandler( - id, - RespondWithJSONFile(fmt.Sprintf("./mocks/data/container_%v.json", file), http.StatusOK), + string(cr.id), + RespondWithJSONFile(containerFile, http.StatusOK), ) } @@ -155,20 +216,6 @@ func getImageHandler(imageId t.ImageID, responseHandler http.HandlerFunc) http.H ) } -func getImageFileHandler(key string) http.HandlerFunc { - if _, found := imageIds[key]; !found { - // The default image (watchtower) is used for most of the containers - key = `default` - } - return getImageHandler(imageIds[key], - RespondWithJSONFile(fmt.Sprintf("./mocks/data/image_%v.json", key), http.StatusOK), - ) -} - -func failTestUnless(ok bool) { - O.ExpectWithOffset(2, ok).To(O.BeTrue(), "test setup failed") -} - // KillContainerHandler mocks the POST containers/{id}/kill endpoint func KillContainerHandler(containerID string, found FoundStatus) http.HandlerFunc { responseHandler := noContentStatusResponse diff --git a/pkg/container/mocks/container_ref.go b/pkg/container/mocks/container_ref.go new file mode 100644 index 0000000..c46eb93 --- /dev/null +++ b/pkg/container/mocks/container_ref.go @@ -0,0 +1,42 @@ +package mocks + +import ( + "fmt" + "os" + + t "github.com/containrrr/watchtower/pkg/types" +) + +type imageRef struct { + id t.ImageID + file string +} + +func (ir *imageRef) getFileName() string { + return fmt.Sprintf("./mocks/data/image_%v.json", ir.file) +} + +type ContainerRef struct { + name string + id t.ContainerID + image *imageRef + file string + references []*ContainerRef + isMissing bool +} + +func (cr *ContainerRef) getContainerFile() (containerFile string, err error) { + file := cr.file + if file == "" { + file = cr.name + } + + containerFile = fmt.Sprintf("./mocks/data/container_%v.json", file) + _, err = os.Stat(containerFile) + + return containerFile, err +} + +func (cr *ContainerRef) ContainerID() t.ContainerID { + return cr.id +} diff --git a/pkg/container/mocks/data/container_net_consumer-missing_supplier.json b/pkg/container/mocks/data/container_net_consumer-missing_supplier.json new file mode 100644 index 0000000..c1a233b --- /dev/null +++ b/pkg/container/mocks/data/container_net_consumer-missing_supplier.json @@ -0,0 +1,205 @@ +{ + "Id": "1f6b79d2aff23244382026c76f4995851322bed5f9c50631620162f6f9aafbd6", + "Created": "2023-07-25T14:55:14.69155887Z", + "Path": "/docker-entrypoint.sh", + "Args": [ + "nginx", + "-g", + "daemon off;" + ], + "State": { + "Status": "running", + "Running": true, + "Paused": false, + "Restarting": false, + "OOMKilled": false, + "Dead": false, + "Pid": 3743, + "ExitCode": 0, + "Error": "", + "StartedAt": "2023-07-25T14:55:15.299654437Z", + "FinishedAt": "0001-01-01T00:00:00Z" + }, + "Image": "sha256:904b8cb13b932e23230836850610fa45dce9eb0650d5618c2b1487c2a4f577b8", + "ResolvConfPath": "/var/lib/docker/containers/25e75393800b5c450a6841212a3b92ed28fa35414a586dec9f2c8a520d4910c2/resolv.conf", + "HostnamePath": "/var/lib/docker/containers/25e75393800b5c450a6841212a3b92ed28fa35414a586dec9f2c8a520d4910c2/hostname", + "HostsPath": "/var/lib/docker/containers/25e75393800b5c450a6841212a3b92ed28fa35414a586dec9f2c8a520d4910c2/hosts", + "LogPath": "/var/lib/docker/containers/1f6b79d2aff23244382026c76f4995851322bed5f9c50631620162f6f9aafbd6/1f6b79d2aff23244382026c76f4995851322bed5f9c50631620162f6f9aafbd6-json.log", + "Name": "/wt-contnet-consumer-1", + "RestartCount": 0, + "Driver": "overlay2", + "Platform": "linux", + "MountLabel": "", + "ProcessLabel": "", + "AppArmorProfile": "", + "ExecIDs": null, + "HostConfig": { + "Binds": null, + "ContainerIDFile": "", + "LogConfig": { + "Type": "json-file", + "Config": {} + }, + "NetworkMode": "container:badc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc1dbadc", + "PortBindings": {}, + "RestartPolicy": { + "Name": "", + "MaximumRetryCount": 0 + }, + "AutoRemove": false, + "VolumeDriver": "", + "VolumesFrom": null, + "ConsoleSize": [ + 0, + 0 + ], + "CapAdd": null, + "CapDrop": null, + "CgroupnsMode": "host", + "Dns": null, + "DnsOptions": null, + "DnsSearch": null, + "ExtraHosts": [], + "GroupAdd": null, + "IpcMode": "private", + "Cgroup": "", + "Links": null, + "OomScoreAdj": 0, + "PidMode": "", + "Privileged": false, + "PublishAllPorts": false, + "ReadonlyRootfs": false, + "SecurityOpt": null, + "UTSMode": "", + "UsernsMode": "", + "ShmSize": 67108864, + "Runtime": "runc", + "Isolation": "", + "CpuShares": 0, + "Memory": 0, + "NanoCpus": 0, + "CgroupParent": "", + "BlkioWeight": 0, + "BlkioWeightDevice": null, + "BlkioDeviceReadBps": null, + "BlkioDeviceWriteBps": null, + "BlkioDeviceReadIOps": null, + "BlkioDeviceWriteIOps": null, + "CpuPeriod": 0, + "CpuQuota": 0, + "CpuRealtimePeriod": 0, + "CpuRealtimeRuntime": 0, + "CpusetCpus": "", + "CpusetMems": "", + "Devices": null, + "DeviceCgroupRules": null, + "DeviceRequests": null, + "MemoryReservation": 0, + "MemorySwap": 0, + "MemorySwappiness": null, + "OomKillDisable": false, + "PidsLimit": null, + "Ulimits": null, + "CpuCount": 0, + "CpuPercent": 0, + "IOMaximumIOps": 0, + "IOMaximumBandwidth": 0, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware" + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + }, + "GraphDriver": { + "Data": { + "LowerDir": "/var/lib/docker/overlay2/05501c86219af9f713c74c129426cf5a17dc5e42f96f7f881f443cab100280e2-init/diff:/var/lib/docker/overlay2/105427179e5628eb7e893d53e21f42f9e76278f8b5665387ecdeed54a7231137/diff:/var/lib/docker/overlay2/09785ba17f27c783ef8b44f369f9aac0ca936000b57abf22b3c54d1e6eb8e27b/diff:/var/lib/docker/overlay2/6f8acd64ae44fd4d14bcb90c105eceba46854aa3985b5b6b317bcc5692cfc286/diff:/var/lib/docker/overlay2/73d41c15edb21c5f12cf53e313f48b5da55283aafc77d35b7bc662241879d7e7/diff:/var/lib/docker/overlay2/d97b55f3d966ae031492369a98e9e00d2bd31e520290fe2034e0a2b1ed77c91e/diff:/var/lib/docker/overlay2/053e9ca65c6b64cb9d98a812ff7488c7e77938b4fb8e0c4d2ad7f8ec235f0f20/diff", + "MergedDir": "/var/lib/docker/overlay2/05501c86219af9f713c74c129426cf5a17dc5e42f96f7f881f443cab100280e2/merged", + "UpperDir": "/var/lib/docker/overlay2/05501c86219af9f713c74c129426cf5a17dc5e42f96f7f881f443cab100280e2/diff", + "WorkDir": "/var/lib/docker/overlay2/05501c86219af9f713c74c129426cf5a17dc5e42f96f7f881f443cab100280e2/work" + }, + "Name": "overlay2" + }, + "Mounts": [], + "Config": { + "Hostname": "25e75393800b", + "Domainname": "", + "User": "", + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "ExposedPorts": { + "80/tcp": {} + }, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "NGINX_VERSION=1.23.3", + "NJS_VERSION=0.7.9", + "PKG_RELEASE=1~bullseye" + ], + "Cmd": [ + "nginx", + "-g", + "daemon off;" + ], + "Image": "nginx", + "Volumes": null, + "WorkingDir": "", + "Entrypoint": [ + "/docker-entrypoint.sh" + ], + "OnBuild": null, + "Labels": { + "com.docker.compose.config-hash": "8bb0e1c8c61f6d495840ba9133ebfb1e4ffda3e1adb701a011b03951848bb9fa", + "com.docker.compose.container-number": "1", + "com.docker.compose.depends_on": "producer:service_started:false", + "com.docker.compose.image": "sha256:904b8cb13b932e23230836850610fa45dce9eb0650d5618c2b1487c2a4f577b8", + "com.docker.compose.oneoff": "False", + "com.docker.compose.project": "wt-contnet", + "com.docker.compose.project.config_files": "/tmp/wt-contnet/docker-compose.yaml", + "com.docker.compose.project.working_dir": "/tmp/wt-contnet", + "com.docker.compose.replace": "07bb70608f96f577aa02b9f317500e23e691c94eb099f6fb52301dfb031d0668", + "com.docker.compose.service": "consumer", + "com.docker.compose.version": "2.19.1", + "desktop.docker.io/wsl-distro": "Ubuntu", + "maintainer": "NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e" + }, + "StopSignal": "SIGQUIT" + }, + "NetworkSettings": { + "Bridge": "", + "SandboxID": "", + "HairpinMode": false, + "LinkLocalIPv6Address": "", + "LinkLocalIPv6PrefixLen": 0, + "Ports": {}, + "SandboxKey": "", + "SecondaryIPAddresses": null, + "SecondaryIPv6Addresses": null, + "EndpointID": "", + "Gateway": "", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "IPAddress": "", + "IPPrefixLen": 0, + "IPv6Gateway": "", + "MacAddress": "", + "Networks": {} + } +} diff --git a/pkg/container/mocks/data/container_net_producer.json b/pkg/container/mocks/data/container_net_supplier.json similarity index 100% rename from pkg/container/mocks/data/container_net_producer.json rename to pkg/container/mocks/data/container_net_supplier.json