Compare commits
68 Commits
v1.2.0-rc1
...
main
Author | SHA1 | Date |
---|---|---|
|
ee7c96f201 | |
|
d0bdb01ee9 | |
|
8338cebec2 | |
|
44a77d77e9 | |
|
277757c333 | |
|
0b7ae2f1b1 | |
|
40b0a08c95 | |
|
7f701df6ab | |
|
a28faab926 | |
|
3f7369aeb9 | |
|
097592d34b | |
|
d2f3f46deb | |
|
3578abe586 | |
|
5f84615a5d | |
|
3b4dfc5dff | |
|
a845cc88d2 | |
|
4c9ae43c0e | |
|
be3f5a9b2d | |
|
f4f2dc7430 | |
|
81ed2d06d6 | |
|
00f4094a12 | |
|
f0289faa47 | |
|
81d15e90c3 | |
|
309b6bbc17 | |
|
692efbd2a7 | |
|
6a68851f26 | |
|
d5c71ad528 | |
|
587837eeda | |
|
425425837e | |
|
c0cc785dbc | |
|
9f73d4da82 | |
|
e82d9969cf | |
|
2c926b5f17 | |
|
ed014fe9dc | |
|
db70b6d343 | |
|
fac588ba52 | |
|
6e57c2ee5d | |
|
499596af1b | |
|
73debca5ce | |
|
9d422db72c | |
|
c28331408d | |
|
1125b83816 | |
|
529bccb346 | |
|
267db7092b | |
|
cebd7dff3a | |
|
6ef571535d | |
|
02ffd013fe | |
|
1e7858f987 | |
|
c04330ee9e | |
|
52babb0dd3 | |
|
9f32fa36f7 | |
|
f5e23f52c0 | |
|
85241009c7 | |
|
e34763a7ec | |
|
f85b8fe31f | |
|
3d7be1bae9 | |
|
df52e9460d | |
|
047255eeed | |
|
0137b32398 | |
|
dd65e2d527 | |
|
bbae2202a6 | |
|
0036b628e1 | |
|
83287db830 | |
|
a67dabb3d0 | |
|
951d8d0e05 | |
|
f846cb72b0 | |
|
e4b261e1a2 | |
|
829ae61c58 |
|
@ -1,4 +1,4 @@
|
|||
FROM alpine:3.19
|
||||
FROM alpine:3.20
|
||||
|
||||
RUN apk add --no-cache curl jq
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Re-Test Action
|
||||
uses: ./.github/actions/retest-action
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
name: Scorecard supply-chain security
|
||||
on:
|
||||
branch_protection_rule:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
schedule:
|
||||
- cron: 29 15 * * 0
|
||||
permissions: read-all
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
permissions:
|
||||
id-token: write
|
||||
security-events: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Run analysis
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
publish_results: true
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@97a0fba1372883ab732affbe8f94b823f91727db # v3.pre.node20
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
- name: Upload to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7
|
||||
with:
|
||||
sarif_file: results.sarif
|
|
@ -4,36 +4,45 @@ name: test
|
|||
on: ["push", "pull_request"]
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.19"
|
||||
GO_VERSION: "1.22"
|
||||
LINUX_ARCHES: "amd64 386 arm arm64 s390x mips64le ppc64le"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ibiqlik/action-yamllint@v3
|
||||
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c # v3.1.1
|
||||
with:
|
||||
format: auto
|
||||
- uses: golangci/golangci-lint-action@v3
|
||||
config_file: .yamllint.yaml
|
||||
|
||||
- uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0
|
||||
with:
|
||||
args: --verbose
|
||||
version: v1.51.2
|
||||
version: v1.57.1
|
||||
|
||||
build:
|
||||
name: Build all linux architectures
|
||||
needs: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Build on all supported architectures
|
||||
run: |
|
||||
|
@ -49,24 +58,23 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Install test binaries
|
||||
env:
|
||||
GO111MODULE: off
|
||||
run: |
|
||||
go get github.com/mattn/goveralls
|
||||
go get github.com/modocache/gover
|
||||
go install github.com/mattn/goveralls@v0.0.12
|
||||
go install github.com/modocache/gover@latest
|
||||
|
||||
- name: test
|
||||
run: COVERALLS=1 ./test.sh
|
||||
|
||||
- name: Send coverage to coveralls
|
||||
env:
|
||||
- env:
|
||||
COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: Send coverage to coveralls
|
||||
run: |
|
||||
PATH=$PATH:$(go env GOPATH)/bin
|
||||
gover
|
||||
|
@ -78,9 +86,11 @@ jobs:
|
|||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: test
|
||||
run: bash ./test.sh
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
.idea/
|
||||
bin/
|
||||
gopath/
|
||||
*.sw[ponm]
|
||||
.vagrant
|
||||
release-*
|
||||
cnitool/cnitool
|
|
@ -3,6 +3,7 @@ extends: default
|
|||
|
||||
rules:
|
||||
document-start: disable
|
||||
line-length: disable
|
||||
truthy:
|
||||
ignore: |
|
||||
.github/workflows/*.yml
|
14
MAINTAINERS
14
MAINTAINERS
|
@ -1,8 +1,14 @@
|
|||
Bruce Ma <brucema19901024@gmail.com> (@mars1024)
|
||||
Casey Callendrello <cdc@isovalent.com> (@squeed)
|
||||
Dan Williams <dcbw@redhat.com> (@dcbw)
|
||||
Matt Dupre <matt@tigera.io> (@matthewdupre)
|
||||
Michael Cambria <mcambria@redhat.com> (@mccv1r0)
|
||||
Michael Zappa <Michael.Zappa@gmail.com> (@MikeZappa87)
|
||||
Piotr Skamruk <piotr.skamruk@gmail.com> (@jellonek)
|
||||
Tomofumi Hayashi <tohayash@redhat.com> (@s1061123)
|
||||
Tomofumi Hayashi <s1061123@gmail.com> (@s1061123)
|
||||
Lionel Jouin <lionel.jouin@est.tech> (@LionelJouin)
|
||||
Ben Leggett <benjamin@edera.dev> (@bleggett)
|
||||
Marcelo Guerrero <guerrero.viveros@gmail.com> (@mlguerrero12)
|
||||
Doug Smith <douglas.kipp.smith@gmail.com> (@dougbtv)
|
||||
|
||||
Emeritus:
|
||||
Dan Williams <dcbw@redhat.com> (@dcbw)
|
||||
Matt Dupre <matt@tigera.io> (@matthewdupre)
|
||||
Piotr Skamruk <piotr.skamruk@gmail.com> (@jellonek)
|
11
README.md
11
README.md
|
@ -4,6 +4,9 @@
|
|||
|
||||
# CNI - the Container Network Interface
|
||||
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/2446)
|
||||
[](https://securityscorecards.dev/viewer/?uri=github.com/containernetworking/cni)
|
||||
|
||||
## What is CNI?
|
||||
|
||||
CNI (_Container Network Interface_), a [Cloud Native Computing Foundation](https://cncf.io) project, consists of a specification and libraries for writing plugins to configure network interfaces in Linux containers, along with a number of supported plugins.
|
||||
|
@ -37,7 +40,6 @@ To avoid duplication, we think it is prudent to define a common interface betwee
|
|||
|
||||
## Who is using CNI?
|
||||
### Container runtimes
|
||||
- [rkt - container engine](https://coreos.com/blog/rkt-cni-networking.html)
|
||||
- [Kubernetes - a system to simplify container operations](https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/)
|
||||
- [OpenShift - Kubernetes with additional enterprise features](https://github.com/openshift/origin/blob/master/docs/openshift_networking_requirements.md)
|
||||
- [Cloud Foundry - a platform for cloud applications](https://github.com/cloudfoundry-incubator/cf-networking-release)
|
||||
|
@ -48,16 +50,13 @@ To avoid duplication, we think it is prudent to define a common interface betwee
|
|||
|
||||
### 3rd party plugins
|
||||
- [Project Calico - a layer 3 virtual network](https://github.com/projectcalico/calico)
|
||||
- [Weave - a multi-host Docker network](https://github.com/weaveworks/weave)
|
||||
- [Contiv Networking - policy networking for various use cases](https://github.com/contiv/netplugin)
|
||||
- [SR-IOV](https://github.com/hustcat/sriov-cni)
|
||||
- [Cilium - BPF & XDP for containers](https://github.com/cilium/cilium)
|
||||
- [Infoblox - enterprise IP address management for containers](https://github.com/infobloxopen/cni-infoblox)
|
||||
- [Cilium - eBPF & XDP for containers](https://github.com/cilium/cilium)
|
||||
- [Multus - a Multi plugin](https://github.com/k8snetworkplumbingwg/multus-cni)
|
||||
- [Romana - Layer 3 CNI plugin supporting network policy for Kubernetes](https://github.com/romana/kube)
|
||||
- [CNI-Genie - generic CNI network plugin](https://github.com/Huawei-PaaS/CNI-Genie)
|
||||
- [Nuage CNI - Nuage Networks SDN plugin for network policy kubernetes support ](https://github.com/nuagenetworks/nuage-cni)
|
||||
- [Silk - a CNI plugin designed for Cloud Foundry](https://github.com/cloudfoundry-incubator/silk)
|
||||
- [Linen - a CNI plugin designed for overlay networks with Open vSwitch and fit in SDN/OpenFlow network environment](https://github.com/John-Lin/linen-cni)
|
||||
- [Vhostuser - a Dataplane network plugin - Supports OVS-DPDK & VPP](https://github.com/intel/vhost-user-net-plugin)
|
||||
- [Amazon ECS CNI Plugins - a collection of CNI Plugins to configure containers with Amazon EC2 elastic network interfaces (ENIs)](https://github.com/aws/amazon-ecs-cni-plugins)
|
||||
|
@ -66,13 +65,11 @@ To avoid duplication, we think it is prudent to define a common interface betwee
|
|||
- [Juniper Contrail](https://www.juniper.net/cloud) / [TungstenFabric](https://tungstenfabric.io) - Provides overlay SDN solution, delivering multicloud networking, hybrid cloud networking, simultaneous overlay-underlay support, network policy enforcement, network isolation, service chaining and flexible load balancing
|
||||
- [Knitter - a CNI plugin supporting multiple networking for Kubernetes](https://github.com/ZTE/Knitter)
|
||||
- [DANM - a CNI-compliant networking solution for TelCo workloads running on Kubernetes](https://github.com/nokia/danm)
|
||||
- [VMware NSX – a CNI plugin that enables automated NSX L2/L3 networking and L4/L7 Load Balancing; network isolation at the pod, node, and cluster level; and zero-trust security policy for your Kubernetes cluster.](https://docs.vmware.com/en/VMware-NSX-T/2.2/com.vmware.nsxt.ncp_kubernetes.doc/GUID-6AFA724E-BB62-4693-B95C-321E8DDEA7E1.html)
|
||||
- [cni-route-override - a meta CNI plugin that override route information](https://github.com/redhat-nfvpe/cni-route-override)
|
||||
- [Terway - a collection of CNI Plugins based on alibaba cloud VPC/ECS network product](https://github.com/AliyunContainerService/terway)
|
||||
- [Cisco ACI CNI - for on-prem and cloud container networking with consistent policy and security model.](https://github.com/noironetworks/aci-containers)
|
||||
- [Kube-OVN - a CNI plugin that bases on OVN/OVS and provides advanced features like subnet, static ip, ACL, QoS, etc.](https://github.com/kubeovn/kube-ovn)
|
||||
- [Project Antrea - an Open vSwitch k8s CNI](https://github.com/vmware-tanzu/antrea)
|
||||
- [OVN4NFV-K8S-Plugin - a OVN based CNI controller plugin to provide cloud native based Service function chaining (SFC), Multiple OVN overlay networking](https://github.com/opnfv/ovn4nfv-k8s-plugin)
|
||||
- [Azure CNI - a CNI plugin that natively extends Azure Virtual Networks to containers](https://github.com/Azure/azure-container-networking)
|
||||
- [Hybridnet - a CNI plugin designed for hybrid clouds which provides both overlay and underlay networking for containers in one or more clusters. Overlay and underlay containers can run on the same node and have cluster-wide bidirectional network connectivity.](https://github.com/alibaba/hybridnet)
|
||||
- [Spiderpool - An IP Address Management (IPAM) CNI plugin of Kubernetes for managing static ip for underlay network](https://github.com/spidernet-io/spiderpool)
|
||||
|
|
27
SPEC.md
27
SPEC.md
|
@ -45,7 +45,7 @@
|
|||
|
||||
## Version
|
||||
|
||||
This is CNI **spec** version **1.1.0-dev**.
|
||||
This is CNI **spec** version **1.1.0**.
|
||||
|
||||
Note that this is **independent from the version of the CNI library and plugins** in this repository (e.g. the versions of [releases](https://github.com/containernetworking/cni/releases)).
|
||||
|
||||
|
@ -109,13 +109,16 @@ A network configuration consists of a JSON object with the following keys:
|
|||
|
||||
- `cniVersion` (string): [Semantic Version 2.0](https://semver.org) of CNI specification to which this configuration list and all the individual configurations conform. Currently "1.1.0"
|
||||
- `cniVersions` (string list): List of all CNI versions which this configuration supports. See [version selection](#version-selection) below.
|
||||
- `name` (string): Network name. This should be unique across all network configurations on a host (or other administrative domain). Must start with an alphanumeric character, optionally followed by any combination of one or more alphanumeric characters, underscore, dot (.) or hyphen (-).
|
||||
- `name` (string): Network name. This should be unique across all network configurations on a host (or other administrative domain). Must start with an alphanumeric character, optionally followed by any combination of one or more alphanumeric characters, underscore, dot (.) or hyphen (-). Must not contain characters disallowed in file paths.
|
||||
- `disableCheck` (boolean): Either `true` or `false`. If `disableCheck` is `true`, runtimes must not call `CHECK` for this network configuration list. This allows an administrator to prevent `CHECK`ing where a combination of plugins is known to return spurious errors.
|
||||
- `plugins` (list): A list of CNI plugins and their configuration, which is a list of plugin configuration objects.
|
||||
- `disableGC` (boolean): Either `true` or `false`. If `disableGC` is `true`, runtimes must not call `GC` for this network configuration list. This allows an administrator to prevent `GC`ing when it is known that garbage collection may have undesired effects (e.g. shared configuration between multiple runtimes).
|
||||
- `loadOnlyInlinedPlugins` (boolean): Either `true` or `false`. If `false` (default), indicates [plugin configuration objects](#plugin-configuration-objects) can be aggregated from multiple sources. Any valid plugin configuration objects aggregated from other sources must be appended to the final list of `plugins` for that network name. If set to `true`, indicates that valid plugin configuration objects aggregated from sources other than the main network configuration will be ignored. If `plugins` is not present in the network configuration, `loadOnlyInlinedPlugins` cannot be set to `true`.
|
||||
- `plugins` (list): A list of inlined [plugin configuration objects](#plugin-configuration-objects). If this key is populated with inlined plugin objects, and `loadOnlyInlinedPlugins` is true, the final set of plugins for a network must consist of all the plugin objects in this list, merged with all the plugins loaded from the sibling folder with the same name as the network.
|
||||
|
||||
#### Plugin configuration objects:
|
||||
Plugin configuration objects may contain additional fields than the ones defined here.
|
||||
The runtime MUST pass through these fields, unchanged, to the plugin, as defined in section 3.
|
||||
Runtimes may aggregate plugin configuration objects from multiple sources, and must unambiguously associate each loaded plugin configuration object with a single, valid network configuration. All aggregated plugin configuration objects must be validated, and each plugin with a valid configuration object must be invoked.
|
||||
|
||||
Plugin configuration objects may contain additional fields beyond the ones defined here. The runtime MUST pass through these fields, unchanged, to the invoked plugin, as defined in section 3.
|
||||
|
||||
**Required keys:**
|
||||
- `type` (string): Matches the name of the CNI plugin binary on disk. Must not contain characters disallowed in file paths for the system (e.g. / or \\).
|
||||
|
@ -146,6 +149,7 @@ Plugins that consume any of these configuration keys should respect their intend
|
|||
Plugins may define additional fields that they accept and may generate an error if called with unknown fields. Runtimes must preserve unknown fields in plugin configuration objects when transforming for execution.
|
||||
|
||||
#### Example configuration
|
||||
The following is an example JSON representation of a network configuration `dbnet` with three plugin configurations (`bridge`, `tuning`, and `portmap`).
|
||||
```jsonc
|
||||
{
|
||||
"cniVersion": "1.1.0",
|
||||
|
@ -157,7 +161,7 @@ Plugins may define additional fields that they accept and may generate an error
|
|||
// plugin specific parameters
|
||||
"bridge": "cni0",
|
||||
"keyA": ["some more", "plugin specific", "configuration"],
|
||||
|
||||
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
// ipam specific
|
||||
|
@ -264,7 +268,10 @@ A CNI plugin, upon receiving a `DEL` command, should either
|
|||
- delete the interface defined by `CNI_IFNAME` inside the container at `CNI_NETNS`, or
|
||||
- undo any modifications applied in the plugin's `ADD` functionality
|
||||
|
||||
Plugins should generally complete a `DEL` action without error even if some resources are missing. For example, an IPAM plugin should generally release an IP allocation and return success even if the container network namespace no longer exists, unless that network namespace is critical for IPAM management. While DHCP may usually send a 'release' message on the container network interface, since DHCP leases have a lifetime this release action would not be considered critical and no error should be returned if this action fails. For another example, the `bridge` plugin should delegate the DEL action to the IPAM plugin and clean up its own resources even if the container network namespace and/or container network interface no longer exist.
|
||||
A `prevResult` must be supplied to CNI plugins as part of a `DEL` command. For the first plugin in the `DEL` command plugin chain, this `prevResult` will be the final result of the previous `ADD` command.
|
||||
Plugins should still return without error if `prevResult` is empty for a `DEL` command, however.
|
||||
|
||||
`DEL` command invocations are always considered best-effort - plugins should always complete a `DEL` action without error to the fullest extent possible, even if some resources or state are missing. For example, an IPAM plugin should generally release an IP allocation and return success even if the container network namespace no longer exists, unless that network namespace is critical for IPAM management. While DHCP may usually send a 'release' message on the container network interface, since DHCP leases have a lifetime this release action would not be considered critical and no error should be returned if this action fails. For another example, the `bridge` plugin should delegate the DEL action to the IPAM plugin and clean up its own resources even if the container network namespace and/or container network interface no longer exist.
|
||||
|
||||
Plugins MUST accept multiple `DEL` calls for the same (`CNI_CONTAINERID`, `CNI_IFNAME`) pair, and return success if the interface in question, or any modifications added, are missing.
|
||||
|
||||
|
@ -384,7 +391,7 @@ The runtime MUST NOT use GC as a substitute for DEL. Plugins may be unable to cl
|
|||
|
||||
The runtime must provide a JSON-serialized plugin configuration object (defined below) on standard in. It contains an additional key;
|
||||
|
||||
- `cni.dev/attachments` (array of objects): The list of **still valid** attachments to this network:
|
||||
- `cni.dev/valid-attachments` (array of objects): The list of **still valid** attachments to this network:
|
||||
- `containerID` (string): the value of CNI_CONTAINERID as provided during the CNI ADD operation
|
||||
- `ifname` (string): the value of CNI_IFNAME as provided during the CNI ADD operation
|
||||
|
||||
|
@ -493,7 +500,7 @@ For attachment-specific operations (ADD, DEL, CHECK), additional field requireme
|
|||
- `capabilities`: must not be set
|
||||
|
||||
For GC operations:
|
||||
- `cni.dev/attachments`: as specified in section 2.
|
||||
- `cni.dev/valid-attachments`: as specified in section 2.
|
||||
|
||||
All other fields not prefixed with `cni.dev/` should be passed through unaltered.
|
||||
|
||||
|
@ -644,6 +651,8 @@ Error Code|Error Description
|
|||
`6`|Failed to decode content. For example, failed to unmarshal network config from bytes or failed to decode version info from string.
|
||||
`7`|Invalid network config. If some validations on network configs do not pass, this error will be raised.
|
||||
`11`|Try again later. If the plugin detects some transient condition that should clear up, it can use this code to notify the runtime it should re-try the operation later.
|
||||
`50`|The plugin is not available (i.e. cannot service `ADD` requests)
|
||||
`51`|The plugin is not available, and existing containers in the network may have limited connectivity.
|
||||
|
||||
In addition, stderr can be used for unstructured output such as logs.
|
||||
|
||||
|
|
|
@ -36,9 +36,11 @@ const (
|
|||
|
||||
DefaultNetDir = "/etc/cni/net.d"
|
||||
|
||||
CmdAdd = "add"
|
||||
CmdCheck = "check"
|
||||
CmdDel = "del"
|
||||
CmdAdd = "add"
|
||||
CmdCheck = "check"
|
||||
CmdDel = "del"
|
||||
CmdGC = "gc"
|
||||
CmdStatus = "status"
|
||||
)
|
||||
|
||||
func parseArgs(args string) ([][2]string, error) {
|
||||
|
@ -66,7 +68,7 @@ func main() {
|
|||
if netdir == "" {
|
||||
netdir = DefaultNetDir
|
||||
}
|
||||
netconf, err := libcni.LoadConfList(netdir, os.Args[2])
|
||||
netconf, err := libcni.LoadNetworkConf(netdir, os.Args[2])
|
||||
if err != nil {
|
||||
exit(err)
|
||||
}
|
||||
|
@ -125,16 +127,23 @@ func main() {
|
|||
exit(err)
|
||||
case CmdDel:
|
||||
exit(cninet.DelNetworkList(context.TODO(), netconf, rt))
|
||||
case CmdGC:
|
||||
// Currently just invoke GC without args, hence all network interface should be GC'ed!
|
||||
exit(cninet.GCNetworkList(context.TODO(), netconf, nil))
|
||||
case CmdStatus:
|
||||
exit(cninet.GetStatusNetworkList(context.TODO(), netconf))
|
||||
}
|
||||
}
|
||||
|
||||
func usage() {
|
||||
exe := filepath.Base(os.Args[0])
|
||||
|
||||
fmt.Fprintf(os.Stderr, "%s: Add, check, or remove network interfaces from a network namespace\n", exe)
|
||||
fmt.Fprintf(os.Stderr, " %s add <net> <netns>\n", exe)
|
||||
fmt.Fprintf(os.Stderr, " %s check <net> <netns>\n", exe)
|
||||
fmt.Fprintf(os.Stderr, " %s del <net> <netns>\n", exe)
|
||||
fmt.Fprintf(os.Stderr, "%s: Add, check, remove, gc or status network interfaces from a network namespace\n", exe)
|
||||
fmt.Fprintf(os.Stderr, " %s add <net> <netns>\n", exe)
|
||||
fmt.Fprintf(os.Stderr, " %s check <net> <netns>\n", exe)
|
||||
fmt.Fprintf(os.Stderr, " %s del <net> <netns>\n", exe)
|
||||
fmt.Fprintf(os.Stderr, " %s gc <net> <netns>\n", exe)
|
||||
fmt.Fprintf(os.Stderr, " %s status <net> <netns>\n", exe)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
|
22
go.mod
22
go.mod
|
@ -1,22 +1,22 @@
|
|||
module github.com/containernetworking/cni
|
||||
|
||||
go 1.18
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/onsi/ginkgo/v2 v2.13.2
|
||||
github.com/onsi/gomega v1.30.0
|
||||
github.com/onsi/ginkgo/v2 v2.20.1
|
||||
github.com/onsi/gomega v1.34.1
|
||||
github.com/vishvananda/netns v0.0.4
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/tools v0.14.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sys v0.23.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
57
go.sum
57
go.sum
|
@ -1,45 +1,36 @@
|
|||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
|
||||
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo=
|
||||
github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
||||
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -23,6 +23,7 @@ package libcni
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -66,17 +67,23 @@ type RuntimeConf struct {
|
|||
CacheDir string
|
||||
}
|
||||
|
||||
type NetworkConfig struct {
|
||||
Network *types.NetConf
|
||||
// Use PluginConfig instead of NetworkConfig, the NetworkConfig
|
||||
// backwards-compat alias will be removed in a future release.
|
||||
type NetworkConfig = PluginConfig
|
||||
|
||||
type PluginConfig struct {
|
||||
Network *types.PluginConf
|
||||
Bytes []byte
|
||||
}
|
||||
|
||||
type NetworkConfigList struct {
|
||||
Name string
|
||||
CNIVersion string
|
||||
DisableCheck bool
|
||||
Plugins []*NetworkConfig
|
||||
Bytes []byte
|
||||
Name string
|
||||
CNIVersion string
|
||||
DisableCheck bool
|
||||
DisableGC bool
|
||||
LoadOnlyInlinedPlugins bool
|
||||
Plugins []*PluginConfig
|
||||
Bytes []byte
|
||||
}
|
||||
|
||||
type NetworkAttachment struct {
|
||||
|
@ -100,19 +107,21 @@ type CNI interface {
|
|||
GetNetworkListCachedResult(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
|
||||
GetNetworkListCachedConfig(net *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
|
||||
|
||||
AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
|
||||
CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
|
||||
DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
|
||||
GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
|
||||
GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
|
||||
AddNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) (types.Result, error)
|
||||
CheckNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error
|
||||
DelNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error
|
||||
GetNetworkCachedResult(net *PluginConfig, rt *RuntimeConf) (types.Result, error)
|
||||
GetNetworkCachedConfig(net *PluginConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
|
||||
|
||||
ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error)
|
||||
ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error)
|
||||
ValidateNetwork(ctx context.Context, net *PluginConfig) ([]string, error)
|
||||
|
||||
GCNetworkList(ctx context.Context, net *NetworkConfigList, args *GCArgs) error
|
||||
GetStatusNetworkList(ctx context.Context, net *NetworkConfigList) error
|
||||
|
||||
GetCachedAttachments(containerID string) ([]*NetworkAttachment, error)
|
||||
|
||||
GetVersionInfo(ctx context.Context, pluginType string) (version.PluginInfo, error)
|
||||
}
|
||||
|
||||
type CNIConfig struct {
|
||||
|
@ -143,7 +152,7 @@ func NewCNIConfigWithCacheDir(path []string, cacheDir string, exec invoke.Exec)
|
|||
}
|
||||
}
|
||||
|
||||
func buildOneConfig(name, cniVersion string, orig *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (*NetworkConfig, error) {
|
||||
func buildOneConfig(name, cniVersion string, orig *PluginConfig, prevResult types.Result, rt *RuntimeConf) (*PluginConfig, error) {
|
||||
var err error
|
||||
|
||||
inject := map[string]interface{}{
|
||||
|
@ -179,7 +188,7 @@ func buildOneConfig(name, cniVersion string, orig *NetworkConfig, prevResult typ
|
|||
// capabilities include "portMappings", and the CapabilityArgs map includes a
|
||||
// "portMappings" key, that key and its value are added to the "runtimeConfig"
|
||||
// dictionary to be passed to the plugin's stdin.
|
||||
func injectRuntimeConfig(orig *NetworkConfig, rt *RuntimeConf) (*NetworkConfig, error) {
|
||||
func injectRuntimeConfig(orig *PluginConfig, rt *RuntimeConf) (*PluginConfig, error) {
|
||||
var err error
|
||||
|
||||
rc := make(map[string]interface{})
|
||||
|
@ -400,7 +409,7 @@ func (c *CNIConfig) GetNetworkListCachedResult(list *NetworkConfigList, rt *Runt
|
|||
|
||||
// GetNetworkCachedResult returns the cached Result of the previous
|
||||
// AddNetwork() operation for a network, or an error.
|
||||
func (c *CNIConfig) GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
|
||||
func (c *CNIConfig) GetNetworkCachedResult(net *PluginConfig, rt *RuntimeConf) (types.Result, error) {
|
||||
return c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||
}
|
||||
|
||||
|
@ -412,7 +421,7 @@ func (c *CNIConfig) GetNetworkListCachedConfig(list *NetworkConfigList, rt *Runt
|
|||
|
||||
// GetNetworkCachedConfig copies the input RuntimeConf to output
|
||||
// RuntimeConf with fields updated with info from the cached Config.
|
||||
func (c *CNIConfig) GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
|
||||
func (c *CNIConfig) GetNetworkCachedConfig(net *PluginConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
|
||||
return c.getCachedConfig(net.Network.Name, rt)
|
||||
}
|
||||
|
||||
|
@ -422,6 +431,9 @@ func (c *CNIConfig) GetCachedAttachments(containerID string) ([]*NetworkAttachme
|
|||
dirPath := filepath.Join(c.getCacheDir(&RuntimeConf{}), "results")
|
||||
entries, err := os.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -475,7 +487,7 @@ func (c *CNIConfig) GetCachedAttachments(containerID string) ([]*NetworkAttachme
|
|||
return attachments, nil
|
||||
}
|
||||
|
||||
func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) {
|
||||
func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *PluginConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) {
|
||||
c.ensureExec()
|
||||
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
|
||||
if err != nil {
|
||||
|
@ -517,7 +529,7 @@ func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList,
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (c *CNIConfig) checkNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) error {
|
||||
func (c *CNIConfig) checkNetwork(ctx context.Context, name, cniVersion string, net *PluginConfig, prevResult types.Result, rt *RuntimeConf) error {
|
||||
c.ensureExec()
|
||||
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
|
||||
if err != nil {
|
||||
|
@ -559,7 +571,7 @@ func (c *CNIConfig) CheckNetworkList(ctx context.Context, list *NetworkConfigLis
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *CNIConfig) delNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) error {
|
||||
func (c *CNIConfig) delNetwork(ctx context.Context, name, cniVersion string, net *PluginConfig, prevResult types.Result, rt *RuntimeConf) error {
|
||||
c.ensureExec()
|
||||
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
|
||||
if err != nil {
|
||||
|
@ -595,14 +607,12 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList,
|
|||
}
|
||||
}
|
||||
|
||||
if cachedResult != nil {
|
||||
_ = c.cacheDel(list.Name, rt)
|
||||
}
|
||||
_ = c.cacheDel(list.Name, rt)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func pluginDescription(net *types.NetConf) string {
|
||||
func pluginDescription(net *types.PluginConf) string {
|
||||
if net == nil {
|
||||
return "<missing>"
|
||||
}
|
||||
|
@ -616,7 +626,7 @@ func pluginDescription(net *types.NetConf) string {
|
|||
}
|
||||
|
||||
// AddNetwork executes the plugin with the ADD command
|
||||
func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
|
||||
func (c *CNIConfig) AddNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) (types.Result, error) {
|
||||
result, err := c.addNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, nil, rt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -630,7 +640,7 @@ func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *Runt
|
|||
}
|
||||
|
||||
// CheckNetwork executes the plugin with the CHECK command
|
||||
func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error {
|
||||
func (c *CNIConfig) CheckNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error {
|
||||
// CHECK was added in CNI spec version 0.4.0 and higher
|
||||
if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil {
|
||||
return err
|
||||
|
@ -646,7 +656,7 @@ func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *Ru
|
|||
}
|
||||
|
||||
// DelNetwork executes the plugin with the DEL command
|
||||
func (c *CNIConfig) DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error {
|
||||
func (c *CNIConfig) DelNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error {
|
||||
var cachedResult types.Result
|
||||
|
||||
// Cached result on DEL was added in CNI spec version 0.4.0 and higher
|
||||
|
@ -706,7 +716,7 @@ func (c *CNIConfig) ValidateNetworkList(ctx context.Context, list *NetworkConfig
|
|||
// ValidateNetwork checks that a configuration is reasonably valid.
|
||||
// It uses the same logic as ValidateNetworkList)
|
||||
// Returns a list of capabilities
|
||||
func (c *CNIConfig) ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error) {
|
||||
func (c *CNIConfig) ValidateNetwork(ctx context.Context, net *PluginConfig) ([]string, error) {
|
||||
caps := []string{}
|
||||
for c, ok := range net.Network.Capabilities {
|
||||
if ok {
|
||||
|
@ -758,15 +768,23 @@ func (c *CNIConfig) GetVersionInfo(ctx context.Context, pluginType string) (vers
|
|||
// - dump the list of cached attachments, and issue deletes as necessary
|
||||
// - issue a GC to the underlying plugins (if the version is high enough)
|
||||
func (c *CNIConfig) GCNetworkList(ctx context.Context, list *NetworkConfigList, args *GCArgs) error {
|
||||
// If DisableGC is set, then don't bother GCing at all.
|
||||
if list.DisableGC {
|
||||
return nil
|
||||
}
|
||||
|
||||
// First, get the list of cached attachments
|
||||
cachedAttachments, err := c.GetCachedAttachments("")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
validAttachments := make(map[types.GCAttachment]interface{}, len(args.ValidAttachments))
|
||||
for _, a := range args.ValidAttachments {
|
||||
validAttachments[a] = nil
|
||||
var validAttachments map[types.GCAttachment]interface{}
|
||||
if args != nil {
|
||||
validAttachments = make(map[types.GCAttachment]interface{}, len(args.ValidAttachments))
|
||||
for _, a := range args.ValidAttachments {
|
||||
validAttachments[a] = nil
|
||||
}
|
||||
}
|
||||
|
||||
var errs []error
|
||||
|
@ -799,10 +817,15 @@ func (c *CNIConfig) GCNetworkList(ctx context.Context, list *NetworkConfigList,
|
|||
// now, if the version supports it, issue a GC
|
||||
if gt, _ := version.GreaterThanOrEqualTo(list.CNIVersion, "1.1.0"); gt {
|
||||
inject := map[string]interface{}{
|
||||
"name": list.Name,
|
||||
"cniVersion": list.CNIVersion,
|
||||
"cni.dev/valid-attachments": args.ValidAttachments,
|
||||
"name": list.Name,
|
||||
"cniVersion": list.CNIVersion,
|
||||
}
|
||||
if args != nil {
|
||||
inject["cni.dev/valid-attachments"] = args.ValidAttachments
|
||||
// #1101: spec used incorrect variable name
|
||||
inject["cni.dev/attachments"] = args.ValidAttachments
|
||||
}
|
||||
|
||||
for _, plugin := range list.Plugins {
|
||||
// build config here
|
||||
pluginConfig, err := InjectConf(plugin, inject)
|
||||
|
@ -815,10 +838,10 @@ func (c *CNIConfig) GCNetworkList(ctx context.Context, list *NetworkConfigList,
|
|||
}
|
||||
}
|
||||
|
||||
return joinErrors(errs...)
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (c *CNIConfig) gcNetwork(ctx context.Context, net *NetworkConfig) error {
|
||||
func (c *CNIConfig) gcNetwork(ctx context.Context, net *PluginConfig) error {
|
||||
c.ensureExec()
|
||||
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
|
||||
if err != nil {
|
||||
|
@ -853,7 +876,7 @@ func (c *CNIConfig) GetStatusNetworkList(ctx context.Context, list *NetworkConfi
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *CNIConfig) getStatusNetwork(ctx context.Context, net *NetworkConfig) error {
|
||||
func (c *CNIConfig) getStatusNetwork(ctx context.Context, net *PluginConfig) error {
|
||||
c.ensureExec()
|
||||
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
|
||||
if err != nil {
|
||||
|
|
|
@ -176,7 +176,7 @@ var _ = Describe("Invoking plugins", func() {
|
|||
pluginConfig []byte
|
||||
cniConfig *libcni.CNIConfig
|
||||
runtimeConfig *libcni.RuntimeConf
|
||||
netConfig *libcni.NetworkConfig
|
||||
netConfig *libcni.PluginConfig
|
||||
ctx context.Context
|
||||
)
|
||||
|
||||
|
@ -295,7 +295,7 @@ var _ = Describe("Invoking plugins", func() {
|
|||
debug *noop_debug.Debug
|
||||
pluginConfig string
|
||||
cniConfig *libcni.CNIConfig
|
||||
netConfig *libcni.NetworkConfig
|
||||
netConfig *libcni.PluginConfig
|
||||
runtimeConfig *libcni.RuntimeConf
|
||||
ctx context.Context
|
||||
|
||||
|
@ -1511,8 +1511,19 @@ var _ = Describe("Invoking plugins", func() {
|
|||
_, err := cniConfig.AddNetworkList(ctx, netConfigList, runtimeConfig)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Issuing a GC with disableGC=true")
|
||||
netConfigList.DisableGC = true
|
||||
gcargs := &libcni.GCArgs{}
|
||||
err = cniConfig.GCNetworkList(ctx, netConfigList, gcargs)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
commands, err := noop_debug.ReadCommandLog(plugins[0].commandFilePath)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(commands).To(HaveLen(1)) // ADD
|
||||
|
||||
By("Issuing a GC with valid networks")
|
||||
gcargs := &libcni.GCArgs{
|
||||
netConfigList.DisableGC = false
|
||||
gcargs = &libcni.GCArgs{
|
||||
ValidAttachments: []types.GCAttachment{{
|
||||
ContainerID: runtimeConfig.ContainerID,
|
||||
IfName: runtimeConfig.IfName,
|
||||
|
@ -1526,7 +1537,7 @@ var _ = Describe("Invoking plugins", func() {
|
|||
err = cniConfig.GCNetworkList(ctx, netConfigList, gcargs)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
commands, err := noop_debug.ReadCommandLog(plugins[0].commandFilePath)
|
||||
commands, err = noop_debug.ReadCommandLog(plugins[0].commandFilePath)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(commands).To(HaveLen(4))
|
||||
|
||||
|
@ -1625,7 +1636,7 @@ var _ = Describe("Invoking plugins", func() {
|
|||
cniBinPath string
|
||||
pluginConfig string
|
||||
cniConfig *libcni.CNIConfig
|
||||
netConfig *libcni.NetworkConfig
|
||||
netConfig *libcni.PluginConfig
|
||||
runtimeConfig *libcni.RuntimeConf
|
||||
netConfigList *libcni.NetworkConfigList
|
||||
)
|
||||
|
@ -1798,7 +1809,7 @@ var _ = Describe("Invoking plugins", func() {
|
|||
cniBinPath string
|
||||
pluginConfig string
|
||||
cniConfig *libcni.CNIConfig
|
||||
netConfig *libcni.NetworkConfig
|
||||
netConfig *libcni.PluginConfig
|
||||
runtimeConfig *libcni.RuntimeConf
|
||||
|
||||
ctx context.Context
|
||||
|
@ -1920,14 +1931,14 @@ var _ = Describe("Invoking plugins", func() {
|
|||
Context("when the RuntimeConf is incomplete", func() {
|
||||
var (
|
||||
testRt *libcni.RuntimeConf
|
||||
testNetConf *libcni.NetworkConfig
|
||||
testNetConf *libcni.PluginConfig
|
||||
testNetConfList *libcni.NetworkConfigList
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
testRt = &libcni.RuntimeConf{}
|
||||
testNetConf = &libcni.NetworkConfig{
|
||||
Network: &types.NetConf{},
|
||||
testNetConf = &libcni.PluginConfig{
|
||||
Network: &types.PluginConf{},
|
||||
}
|
||||
testNetConfList = &libcni.NetworkConfigList{}
|
||||
})
|
||||
|
|
224
libcni/conf.go
224
libcni/conf.go
|
@ -20,11 +20,10 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/containernetworking/cni/pkg/version"
|
||||
)
|
||||
|
@ -46,9 +45,16 @@ func (e NoConfigsFoundError) Error() string {
|
|||
return fmt.Sprintf(`no net configurations found in %s`, e.Dir)
|
||||
}
|
||||
|
||||
func ConfFromBytes(bytes []byte) (*NetworkConfig, error) {
|
||||
conf := &NetworkConfig{Bytes: bytes, Network: &types.NetConf{}}
|
||||
if err := json.Unmarshal(bytes, conf.Network); err != nil {
|
||||
// This will not validate that the plugins actually belong to the netconfig by ensuring
|
||||
// that they are loaded from a directory named after the networkName, relative to the network config.
|
||||
//
|
||||
// Since here we are just accepting raw bytes, the caller is responsible for ensuring that the plugin
|
||||
// config provided here actually "belongs" to the networkconfig in question.
|
||||
func NetworkPluginConfFromBytes(pluginConfBytes []byte) (*PluginConfig, error) {
|
||||
// TODO why are we creating a struct that holds both the byte representation and the deserialized
|
||||
// representation, and returning that, instead of just returning the deserialized representation?
|
||||
conf := &PluginConfig{Bytes: pluginConfBytes, Network: &types.PluginConf{}}
|
||||
if err := json.Unmarshal(pluginConfBytes, conf.Network); err != nil {
|
||||
return nil, fmt.Errorf("error parsing configuration: %w", err)
|
||||
}
|
||||
if conf.Network.Type == "" {
|
||||
|
@ -57,17 +63,35 @@ func ConfFromBytes(bytes []byte) (*NetworkConfig, error) {
|
|||
return conf, nil
|
||||
}
|
||||
|
||||
func ConfFromFile(filename string) (*NetworkConfig, error) {
|
||||
bytes, err := os.ReadFile(filename)
|
||||
// Given a path to a directory containing a network configuration, and the name of a network,
|
||||
// loads all plugin definitions found at path `networkConfPath/networkName/*.conf`
|
||||
func NetworkPluginConfsFromFiles(networkConfPath, networkName string) ([]*PluginConfig, error) {
|
||||
var pConfs []*PluginConfig
|
||||
|
||||
pluginConfPath := filepath.Join(networkConfPath, networkName)
|
||||
|
||||
pluginConfFiles, err := ConfFiles(pluginConfPath, []string{".conf"})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s: %w", filename, err)
|
||||
return nil, fmt.Errorf("failed to read plugin config files in %s: %w", pluginConfPath, err)
|
||||
}
|
||||
return ConfFromBytes(bytes)
|
||||
|
||||
for _, pluginConfFile := range pluginConfFiles {
|
||||
pluginConfBytes, err := os.ReadFile(pluginConfFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s: %w", pluginConfFile, err)
|
||||
}
|
||||
pluginConf, err := NetworkPluginConfFromBytes(pluginConfBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pConfs = append(pConfs, pluginConf)
|
||||
}
|
||||
return pConfs, nil
|
||||
}
|
||||
|
||||
func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
|
||||
func NetworkConfFromBytes(confBytes []byte) (*NetworkConfigList, error) {
|
||||
rawList := make(map[string]interface{})
|
||||
if err := json.Unmarshal(bytes, &rawList); err != nil {
|
||||
if err := json.Unmarshal(confBytes, &rawList); err != nil {
|
||||
return nil, fmt.Errorf("error parsing configuration list: %w", err)
|
||||
}
|
||||
|
||||
|
@ -92,24 +116,20 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
|
|||
rawVersions, ok := rawList["cniVersions"]
|
||||
if ok {
|
||||
// Parse the current package CNI version
|
||||
currentVersion, err := semver.NewVersion(version.Current())
|
||||
if err != nil {
|
||||
panic("CNI version is invalid semver!")
|
||||
}
|
||||
|
||||
rvs, ok := rawVersions.([]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("error parsing configuration list: invalid type for cniVersions: %T", rvs)
|
||||
}
|
||||
vs := make([]*semver.Version, 0, len(rvs))
|
||||
vs := make([]string, 0, len(rvs))
|
||||
for i, rv := range rvs {
|
||||
v, ok := rv.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("error parsing configuration list: invalid type for cniVersions index %d: %T", i, rv)
|
||||
}
|
||||
if v, err := semver.NewVersion(v); err != nil {
|
||||
gt, err := version.GreaterThan(v, version.Current())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing configuration list: invalid cniVersions entry %s at index %d: %w", v, i, err)
|
||||
} else if !v.GreaterThan(currentVersion) {
|
||||
} else if !gt {
|
||||
// Skip versions "greater" than this implementation of the spec
|
||||
vs = append(vs, v)
|
||||
}
|
||||
|
@ -117,50 +137,91 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
|
|||
|
||||
// if cniVersion was already set, append it to the list for sorting.
|
||||
if cniVersion != "" {
|
||||
if v, err := semver.NewVersion(cniVersion); err != nil {
|
||||
gt, err := version.GreaterThan(cniVersion, version.Current())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing configuration list: invalid cniVersion %s: %w", cniVersion, err)
|
||||
} else if !v.GreaterThan(currentVersion) {
|
||||
} else if !gt {
|
||||
// ignore any versions higher than the current implemented spec version
|
||||
vs = append(vs, v)
|
||||
vs = append(vs, cniVersion)
|
||||
}
|
||||
}
|
||||
sort.Sort(semver.Collection(vs))
|
||||
slices.SortFunc[[]string](vs, func(v1, v2 string) int {
|
||||
if v1 == v2 {
|
||||
return 0
|
||||
}
|
||||
if gt, _ := version.GreaterThan(v1, v2); gt {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
})
|
||||
if len(vs) > 0 {
|
||||
cniVersion = vs[len(vs)-1].String()
|
||||
cniVersion = vs[len(vs)-1]
|
||||
}
|
||||
}
|
||||
|
||||
disableCheck := false
|
||||
if rawDisableCheck, ok := rawList["disableCheck"]; ok {
|
||||
disableCheck, ok = rawDisableCheck.(bool)
|
||||
readBool := func(key string) (bool, error) {
|
||||
rawVal, ok := rawList[key]
|
||||
if !ok {
|
||||
disableCheckStr, ok := rawDisableCheck.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("error parsing configuration list: invalid disableCheck type %T", rawDisableCheck)
|
||||
}
|
||||
switch {
|
||||
case strings.ToLower(disableCheckStr) == "false":
|
||||
disableCheck = false
|
||||
case strings.ToLower(disableCheckStr) == "true":
|
||||
disableCheck = true
|
||||
default:
|
||||
return nil, fmt.Errorf("error parsing configuration list: invalid disableCheck value %q", disableCheckStr)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
if b, ok := rawVal.(bool); ok {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
s, ok := rawVal.(string)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("error parsing configuration list: invalid type %T for %s", rawVal, key)
|
||||
}
|
||||
s = strings.ToLower(s)
|
||||
switch s {
|
||||
case "false":
|
||||
return false, nil
|
||||
case "true":
|
||||
return true, nil
|
||||
}
|
||||
return false, fmt.Errorf("error parsing configuration list: invalid value %q for %s", s, key)
|
||||
}
|
||||
|
||||
disableCheck, err := readBool("disableCheck")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
disableGC, err := readBool("disableGC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loadOnlyInlinedPlugins, err := readBool("loadOnlyInlinedPlugins")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := &NetworkConfigList{
|
||||
Name: name,
|
||||
DisableCheck: disableCheck,
|
||||
CNIVersion: cniVersion,
|
||||
Bytes: bytes,
|
||||
Name: name,
|
||||
DisableCheck: disableCheck,
|
||||
DisableGC: disableGC,
|
||||
LoadOnlyInlinedPlugins: loadOnlyInlinedPlugins,
|
||||
CNIVersion: cniVersion,
|
||||
Bytes: confBytes,
|
||||
}
|
||||
|
||||
var plugins []interface{}
|
||||
plug, ok := rawList["plugins"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("error parsing configuration list: no 'plugins' key")
|
||||
// We can have a `plugins` list key in the main conf,
|
||||
// We can also have `loadOnlyInlinedPlugins == true`
|
||||
//
|
||||
// If `plugins` is there, then `loadOnlyInlinedPlugins` can be true
|
||||
//
|
||||
// If plugins is NOT there, then `loadOnlyInlinedPlugins` cannot be true
|
||||
//
|
||||
// We have to have at least some plugins.
|
||||
if !ok && loadOnlyInlinedPlugins {
|
||||
return nil, fmt.Errorf("error parsing configuration list: `loadOnlyInlinedPlugins` is true, and no 'plugins' key")
|
||||
} else if !ok && !loadOnlyInlinedPlugins {
|
||||
return list, nil
|
||||
}
|
||||
|
||||
plugins, ok = plug.([]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("error parsing configuration list: invalid 'plugins' type %T", plug)
|
||||
|
@ -180,24 +241,68 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
|
|||
}
|
||||
list.Plugins = append(list.Plugins, netConf)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func ConfListFromFile(filename string) (*NetworkConfigList, error) {
|
||||
func NetworkConfFromFile(filename string) (*NetworkConfigList, error) {
|
||||
bytes, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s: %w", filename, err)
|
||||
}
|
||||
return ConfListFromBytes(bytes)
|
||||
|
||||
conf, err := NetworkConfFromBytes(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !conf.LoadOnlyInlinedPlugins {
|
||||
plugins, err := NetworkPluginConfsFromFiles(filepath.Dir(filename), conf.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf.Plugins = append(conf.Plugins, plugins...)
|
||||
}
|
||||
|
||||
if len(conf.Plugins) == 0 {
|
||||
// Having 0 plugins for a given network is not necessarily a problem,
|
||||
// but return as error for caller to decide, since they tried to load
|
||||
return nil, fmt.Errorf("no plugin configs found")
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
// Deprecated: This file format is no longer supported, use NetworkConfXXX and NetworkPluginXXX functions
|
||||
func ConfFromBytes(bytes []byte) (*NetworkConfig, error) {
|
||||
return NetworkPluginConfFromBytes(bytes)
|
||||
}
|
||||
|
||||
// Deprecated: This file format is no longer supported, use NetworkConfXXX and NetworkPluginXXX functions
|
||||
func ConfFromFile(filename string) (*NetworkConfig, error) {
|
||||
bytes, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s: %w", filename, err)
|
||||
}
|
||||
return ConfFromBytes(bytes)
|
||||
}
|
||||
|
||||
func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
|
||||
return NetworkConfFromBytes(bytes)
|
||||
}
|
||||
|
||||
func ConfListFromFile(filename string) (*NetworkConfigList, error) {
|
||||
return NetworkConfFromFile(filename)
|
||||
}
|
||||
|
||||
// ConfFiles simply returns a slice of all files in the provided directory
|
||||
// with extensions matching the provided set.
|
||||
func ConfFiles(dir string, extensions []string) ([]string, error) {
|
||||
// In part, adapted from rkt/networking/podenv.go#listFiles
|
||||
files, err := os.ReadDir(dir)
|
||||
switch {
|
||||
case err == nil: // break
|
||||
case os.IsNotExist(err):
|
||||
// If folder not there, return no error - only return an
|
||||
// error if we cannot read contents or there are no contents.
|
||||
return nil, nil
|
||||
default:
|
||||
return nil, err
|
||||
|
@ -218,6 +323,7 @@ func ConfFiles(dir string, extensions []string) ([]string, error) {
|
|||
return confFiles, nil
|
||||
}
|
||||
|
||||
// Deprecated: This file format is no longer supported, use NetworkConfXXX and NetworkPluginXXX functions
|
||||
func LoadConf(dir, name string) (*NetworkConfig, error) {
|
||||
files, err := ConfFiles(dir, []string{".conf", ".json"})
|
||||
switch {
|
||||
|
@ -241,6 +347,15 @@ func LoadConf(dir, name string) (*NetworkConfig, error) {
|
|||
}
|
||||
|
||||
func LoadConfList(dir, name string) (*NetworkConfigList, error) {
|
||||
return LoadNetworkConf(dir, name)
|
||||
}
|
||||
|
||||
// LoadNetworkConf looks at all the network configs in a given dir,
|
||||
// loads and parses them all, and returns the first one with an extension of `.conf`
|
||||
// that matches the provided network name predicate.
|
||||
func LoadNetworkConf(dir, name string) (*NetworkConfigList, error) {
|
||||
// TODO this .conflist/.conf extension thing is confusing and inexact
|
||||
// for implementors. We should pick one extension for everything and stick with it.
|
||||
files, err := ConfFiles(dir, []string{".conflist"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -248,7 +363,7 @@ func LoadConfList(dir, name string) (*NetworkConfigList, error) {
|
|||
sort.Strings(files)
|
||||
|
||||
for _, confFile := range files {
|
||||
conf, err := ConfListFromFile(confFile)
|
||||
conf, err := NetworkConfFromFile(confFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -257,7 +372,7 @@ func LoadConfList(dir, name string) (*NetworkConfigList, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Try and load a network configuration file (instead of list)
|
||||
// Deprecated: Try and load a network configuration file (instead of list)
|
||||
// from the same name, then upconvert.
|
||||
singleConf, err := LoadConf(dir, name)
|
||||
if err != nil {
|
||||
|
@ -273,7 +388,8 @@ func LoadConfList(dir, name string) (*NetworkConfigList, error) {
|
|||
return ConfListFromConf(singleConf)
|
||||
}
|
||||
|
||||
func InjectConf(original *NetworkConfig, newValues map[string]interface{}) (*NetworkConfig, error) {
|
||||
// InjectConf takes a PluginConfig and inserts additional values into it, ensuring the result is serializable.
|
||||
func InjectConf(original *PluginConfig, newValues map[string]interface{}) (*PluginConfig, error) {
|
||||
config := make(map[string]interface{})
|
||||
err := json.Unmarshal(original.Bytes, &config)
|
||||
if err != nil {
|
||||
|
@ -297,12 +413,14 @@ func InjectConf(original *NetworkConfig, newValues map[string]interface{}) (*Net
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return ConfFromBytes(newBytes)
|
||||
return NetworkPluginConfFromBytes(newBytes)
|
||||
}
|
||||
|
||||
// ConfListFromConf "upconverts" a network config in to a NetworkConfigList,
|
||||
// with the single network as the only entry in the list.
|
||||
func ConfListFromConf(original *NetworkConfig) (*NetworkConfigList, error) {
|
||||
//
|
||||
// Deprecated: Non-conflist file formats are unsupported, use NetworkConfXXX and NetworkPluginXXX functions
|
||||
func ConfListFromConf(original *PluginConfig) (*NetworkConfigList, error) {
|
||||
// Re-deserialize the config's json, then make a raw map configlist.
|
||||
// This may seem a bit strange, but it's to make the Bytes fields
|
||||
// actually make sense. Otherwise, the generated json is littered with
|
||||
|
|
|
@ -50,8 +50,8 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
It("finds the network config file for the plugin of the given type", func() {
|
||||
netConfig, err := libcni.LoadConf(configDir, "some-plugin")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfig).To(Equal(&libcni.NetworkConfig{
|
||||
Network: &types.NetConf{
|
||||
Expect(netConfig).To(Equal(&libcni.PluginConfig{
|
||||
Network: &types.PluginConf{
|
||||
Name: "some-plugin",
|
||||
Type: "foobar",
|
||||
},
|
||||
|
@ -79,8 +79,8 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
It("finds the network config file for the plugin of the given type", func() {
|
||||
netConfig, err := libcni.LoadConf(configDir, "some-plugin")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfig).To(Equal(&libcni.NetworkConfig{
|
||||
Network: &types.NetConf{
|
||||
Expect(netConfig).To(Equal(&libcni.PluginConfig{
|
||||
Network: &types.PluginConf{
|
||||
Name: "some-plugin",
|
||||
Type: "foobar",
|
||||
},
|
||||
|
@ -181,7 +181,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
})
|
||||
})
|
||||
|
||||
Describe("ConfFromBytes", func() {
|
||||
Describe("NetworkPluginConfFromBytes", func() {
|
||||
Context("when the config is missing 'type'", func() {
|
||||
It("returns a useful error", func() {
|
||||
_, err := libcni.ConfFromBytes([]byte(`{ "name": "some-plugin", "some-key": "some-value" }`))
|
||||
|
@ -190,7 +190,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
})
|
||||
})
|
||||
|
||||
Describe("LoadConfList", func() {
|
||||
Describe("LoadNetworkConf", func() {
|
||||
var (
|
||||
configDir string
|
||||
configList []byte
|
||||
|
@ -202,7 +202,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
configList = []byte(`{
|
||||
"name": "some-list",
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.2.0",
|
||||
"disableCheck": true,
|
||||
"plugins": [
|
||||
|
@ -228,23 +228,23 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
})
|
||||
|
||||
It("finds the network config file for the plugin of the given type", func() {
|
||||
netConfigList, err := libcni.LoadConfList(configDir, "some-list")
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList).To(Equal(&libcni.NetworkConfigList{
|
||||
Name: "some-list",
|
||||
Name: "some-network",
|
||||
CNIVersion: "0.2.0",
|
||||
DisableCheck: true,
|
||||
Plugins: []*libcni.NetworkConfig{
|
||||
Plugins: []*libcni.PluginConfig{
|
||||
{
|
||||
Network: &types.NetConf{Type: "host-local"},
|
||||
Network: &types.PluginConf{Type: "host-local"},
|
||||
Bytes: []byte(`{"subnet":"10.0.0.1/24","type":"host-local"}`),
|
||||
},
|
||||
{
|
||||
Network: &types.NetConf{Type: "bridge"},
|
||||
Network: &types.PluginConf{Type: "bridge"},
|
||||
Bytes: []byte(`{"mtu":1400,"type":"bridge"}`),
|
||||
},
|
||||
{
|
||||
Network: &types.NetConf{Type: "port-forwarding"},
|
||||
Network: &types.PluginConf{Type: "port-forwarding"},
|
||||
Bytes: []byte(`{"ports":{"20.0.0.1:8080":"80"},"type":"port-forwarding"}`),
|
||||
},
|
||||
},
|
||||
|
@ -255,7 +255,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
Context("when there is a config file with the same name as the list", func() {
|
||||
BeforeEach(func() {
|
||||
configFile := []byte(`{
|
||||
"name": "some-list",
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.2.0",
|
||||
"type": "bridge"
|
||||
}`)
|
||||
|
@ -263,7 +263,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
})
|
||||
|
||||
It("Loads the config list first", func() {
|
||||
netConfigList, err := libcni.LoadConfList(configDir, "some-list")
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList.Plugins).To(HaveLen(3))
|
||||
})
|
||||
|
@ -271,7 +271,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
It("falls back to the config file", func() {
|
||||
Expect(os.Remove(filepath.Join(configDir, "50-whatever.conflist"))).To(Succeed())
|
||||
|
||||
netConfigList, err := libcni.LoadConfList(configDir, "some-list")
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList.Plugins).To(HaveLen(1))
|
||||
Expect(netConfigList.Plugins[0].Network.Type).To(Equal("bridge"))
|
||||
|
@ -284,15 +284,15 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
})
|
||||
|
||||
It("returns a useful error", func() {
|
||||
_, err := libcni.LoadConfList(configDir, "some-plugin")
|
||||
_, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).To(MatchError(libcni.NoConfigsFoundError{Dir: configDir}))
|
||||
})
|
||||
})
|
||||
|
||||
Context("when there is no config for the desired plugin list", func() {
|
||||
Context("when there is no config for the desired network name", func() {
|
||||
It("returns a useful error", func() {
|
||||
_, err := libcni.LoadConfList(configDir, "some-other-plugin")
|
||||
Expect(err).To(MatchError(libcni.NotFoundError{Dir: configDir, Name: "some-other-plugin"}))
|
||||
_, err := libcni.LoadNetworkConf(configDir, "some-other-network")
|
||||
Expect(err).To(MatchError(libcni.NotFoundError{Dir: configDir, Name: "some-other-network"}))
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -302,7 +302,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
})
|
||||
|
||||
It("returns a useful error", func() {
|
||||
_, err := libcni.LoadConfList(configDir, "some-plugin")
|
||||
_, err := libcni.LoadNetworkConf(configDir, "some-plugin")
|
||||
Expect(err).To(MatchError(`error parsing configuration list: unexpected end of JSON input`))
|
||||
})
|
||||
})
|
||||
|
@ -326,7 +326,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
})
|
||||
|
||||
It("will not find the config", func() {
|
||||
_, err := libcni.LoadConfList(configDir, "deep")
|
||||
_, err := libcni.LoadNetworkConf(configDir, "deep")
|
||||
Expect(err).To(MatchError(HavePrefix("no net configuration with name")))
|
||||
})
|
||||
})
|
||||
|
@ -334,7 +334,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
Context("when disableCheck is a string not a boolean", func() {
|
||||
It("will read a 'true' value and convert to boolean", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-list",
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"disableCheck": "true",
|
||||
"plugins": [
|
||||
|
@ -346,14 +346,14 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
}`)
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
netConfigList, err := libcni.LoadConfList(configDir, "some-list")
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList.DisableCheck).To(BeTrue())
|
||||
})
|
||||
|
||||
It("will read a 'false' value and convert to boolean", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-list",
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"disableCheck": "false",
|
||||
"plugins": [
|
||||
|
@ -365,7 +365,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
}`)
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
netConfigList, err := libcni.LoadConfList(configDir, "some-list")
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList.DisableCheck).To(BeFalse())
|
||||
})
|
||||
|
@ -373,7 +373,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
It("will return an error on an unrecognized value", func() {
|
||||
const badValue string = "adsfasdfasf"
|
||||
configList = []byte(fmt.Sprintf(`{
|
||||
"name": "some-list",
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"disableCheck": "%s",
|
||||
"plugins": [
|
||||
|
@ -385,35 +385,244 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
}`, badValue))
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
_, err := libcni.LoadConfList(configDir, "some-list")
|
||||
Expect(err).To(MatchError(fmt.Sprintf("error parsing configuration list: invalid disableCheck value \"%s\"", badValue)))
|
||||
_, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).To(MatchError(fmt.Sprintf("error parsing configuration list: invalid value \"%s\" for disableCheck", badValue)))
|
||||
})
|
||||
})
|
||||
|
||||
Context("for loadOnlyInlinedPlugins", func() {
|
||||
It("the value will be parsed", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"loadOnlyInlinedPlugins": true,
|
||||
"plugins": [
|
||||
{
|
||||
"type": "host-local",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
dirPluginConf := []byte(`{
|
||||
"type": "bro-check-out-my-plugin",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}`)
|
||||
|
||||
subDir := filepath.Join(configDir, "some-network")
|
||||
Expect(os.MkdirAll(subDir, 0o700)).To(Succeed())
|
||||
Expect(os.WriteFile(filepath.Join(subDir, "funky-second-plugin.conf"), dirPluginConf, 0o600)).To(Succeed())
|
||||
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList.LoadOnlyInlinedPlugins).To(BeTrue())
|
||||
})
|
||||
|
||||
It("the value will be false if not in config", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"plugins": [
|
||||
{
|
||||
"type": "host-local",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList.LoadOnlyInlinedPlugins).To(BeFalse())
|
||||
})
|
||||
|
||||
It("will return an error on an unrecognized value", func() {
|
||||
const badValue string = "sphagnum"
|
||||
configList = []byte(fmt.Sprintf(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"loadOnlyInlinedPlugins": "%s",
|
||||
"plugins": [
|
||||
{
|
||||
"type": "host-local",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}`, badValue))
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
_, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).To(MatchError(fmt.Sprintf(`error parsing configuration list: invalid value "%s" for loadOnlyInlinedPlugins`, badValue)))
|
||||
})
|
||||
|
||||
It("will return an error if `plugins` is missing and `loadOnlyInlinedPlugins` is `true`", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"loadOnlyInlinedPlugins": true
|
||||
}`)
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
_, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).To(MatchError("error parsing configuration list: `loadOnlyInlinedPlugins` is true, and no 'plugins' key"))
|
||||
})
|
||||
|
||||
It("will return no error if `plugins` is missing and `loadOnlyInlinedPlugins` is false", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"loadOnlyInlinedPlugins": false
|
||||
}`)
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
dirPluginConf := []byte(`{
|
||||
"type": "bro-check-out-my-plugin",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}`)
|
||||
|
||||
subDir := filepath.Join(configDir, "some-network")
|
||||
Expect(os.MkdirAll(subDir, 0o700)).To(Succeed())
|
||||
Expect(os.WriteFile(filepath.Join(subDir, "funky-second-plugin.conf"), dirPluginConf, 0o600)).To(Succeed())
|
||||
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList.LoadOnlyInlinedPlugins).To(BeFalse())
|
||||
Expect(netConfigList.Plugins).To(HaveLen(1))
|
||||
})
|
||||
|
||||
It("will return error if `loadOnlyInlinedPlugins` is implicitly false + no conf plugin is defined, but no plugins subfolder with network name exists", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0"
|
||||
}`)
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
_, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).To(MatchError("no plugin configs found"))
|
||||
})
|
||||
|
||||
It("will return NO error if `loadOnlyInlinedPlugins` is implicitly false + at least 1 conf plugin is defined, but no plugins subfolder with network name exists", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"plugins": [
|
||||
{
|
||||
"type": "host-local",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
_, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("will return NO error if `loadOnlyInlinedPlugins` is implicitly false + at least 1 conf plugin is defined and network name subfolder exists, but is empty/unreadable", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"plugins": [
|
||||
{
|
||||
"type": "host-local",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
subDir := filepath.Join(configDir, "some-network")
|
||||
Expect(os.MkdirAll(subDir, 0o700)).To(Succeed())
|
||||
|
||||
_, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("will merge loaded and inlined plugin lists if both `plugins` is set and `loadOnlyInlinedPlugins` is false", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"plugins": [
|
||||
{
|
||||
"type": "host-local",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
dirPluginConf := []byte(`{
|
||||
"type": "bro-check-out-my-plugin",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}`)
|
||||
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
|
||||
subDir := filepath.Join(configDir, "some-network")
|
||||
Expect(os.MkdirAll(subDir, 0o700)).To(Succeed())
|
||||
Expect(os.WriteFile(filepath.Join(subDir, "funky-second-plugin.conf"), dirPluginConf, 0o600)).To(Succeed())
|
||||
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList.LoadOnlyInlinedPlugins).To(BeFalse())
|
||||
Expect(netConfigList.Plugins).To(HaveLen(2))
|
||||
})
|
||||
|
||||
It("will ignore loaded plugins if `plugins` is set and `loadOnlyInlinedPlugins` is true", func() {
|
||||
configList = []byte(`{
|
||||
"name": "some-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"loadOnlyInlinedPlugins": true,
|
||||
"plugins": [
|
||||
{
|
||||
"type": "host-local",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
dirPluginConf := []byte(`{
|
||||
"type": "bro-check-out-my-plugin",
|
||||
"subnet": "10.0.0.1/24"
|
||||
}`)
|
||||
|
||||
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
|
||||
subDir := filepath.Join(configDir, "some-network")
|
||||
Expect(os.MkdirAll(subDir, 0o700)).To(Succeed())
|
||||
Expect(os.WriteFile(filepath.Join(subDir, "funky-second-plugin.conf"), dirPluginConf, 0o600)).To(Succeed())
|
||||
|
||||
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(netConfigList.LoadOnlyInlinedPlugins).To(BeTrue())
|
||||
Expect(netConfigList.Plugins).To(HaveLen(1))
|
||||
Expect(netConfigList.Plugins[0].Network.Type).To(Equal("host-local"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("ConfListFromFile", func() {
|
||||
Describe("NetworkConfFromFile", func() {
|
||||
Context("when the file cannot be opened", func() {
|
||||
It("returns a useful error", func() {
|
||||
_, err := libcni.ConfListFromFile("/tmp/nope/not-here")
|
||||
_, err := libcni.NetworkConfFromFile("/tmp/nope/not-here")
|
||||
Expect(err).To(MatchError(HavePrefix(`error reading /tmp/nope/not-here: open /tmp/nope/not-here`)))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("InjectConf", func() {
|
||||
var testNetConfig *libcni.NetworkConfig
|
||||
var testNetConfig *libcni.PluginConfig
|
||||
|
||||
BeforeEach(func() {
|
||||
testNetConfig = &libcni.NetworkConfig{
|
||||
Network: &types.NetConf{Name: "some-plugin", Type: "foobar"},
|
||||
testNetConfig = &libcni.PluginConfig{
|
||||
Network: &types.PluginConf{Name: "some-plugin", Type: "foobar"},
|
||||
Bytes: []byte(`{ "name": "some-plugin", "type": "foobar" }`),
|
||||
}
|
||||
})
|
||||
|
||||
Context("when function parameters are incorrect", func() {
|
||||
It("returns unmarshal error", func() {
|
||||
conf := &libcni.NetworkConfig{
|
||||
Network: &types.NetConf{Name: "some-plugin"},
|
||||
conf := &libcni.PluginConfig{
|
||||
Network: &types.PluginConf{Name: "some-plugin"},
|
||||
Bytes: []byte(`{ cc cc cc}`),
|
||||
}
|
||||
|
||||
|
@ -438,8 +647,8 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
|
||||
resultConfig, err := libcni.InjectConf(testNetConfig, map[string]interface{}{"test": "test"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(resultConfig).To(Equal(&libcni.NetworkConfig{
|
||||
Network: &types.NetConf{
|
||||
Expect(resultConfig).To(Equal(&libcni.PluginConfig{
|
||||
Network: &types.PluginConf{
|
||||
Name: "some-plugin",
|
||||
Type: "foobar",
|
||||
},
|
||||
|
@ -456,8 +665,8 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
resultConfig, err = libcni.InjectConf(resultConfig, map[string]interface{}{"test": "changedValue"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(resultConfig).To(Equal(&libcni.NetworkConfig{
|
||||
Network: &types.NetConf{
|
||||
Expect(resultConfig).To(Equal(&libcni.PluginConfig{
|
||||
Network: &types.PluginConf{
|
||||
Name: "some-plugin",
|
||||
Type: "foobar",
|
||||
},
|
||||
|
@ -474,8 +683,8 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
resultConfig, err = libcni.InjectConf(resultConfig, map[string]interface{}{"test": "test"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(resultConfig).To(Equal(&libcni.NetworkConfig{
|
||||
Network: &types.NetConf{
|
||||
Expect(resultConfig).To(Equal(&libcni.PluginConfig{
|
||||
Network: &types.PluginConf{
|
||||
Name: "some-plugin",
|
||||
Type: "foobar",
|
||||
},
|
||||
|
@ -496,8 +705,8 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
resultConfig, err = libcni.InjectConf(resultConfig, map[string]interface{}{"type": "bridge"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(resultConfig).To(Equal(&libcni.NetworkConfig{
|
||||
Network: &types.NetConf{Name: "some-plugin", Type: "bridge", DNS: types.DNS{Nameservers: servers, Domain: "local"}},
|
||||
Expect(resultConfig).To(Equal(&libcni.PluginConfig{
|
||||
Network: &types.PluginConf{Name: "some-plugin", Type: "bridge", DNS: types.DNS{Nameservers: servers, Domain: "local"}},
|
||||
Bytes: expectedPluginConfig,
|
||||
}))
|
||||
})
|
||||
|
@ -505,7 +714,7 @@ var _ = Describe("Loading configuration from disk", func() {
|
|||
})
|
||||
})
|
||||
|
||||
var _ = Describe("ConfListFromBytes", func() {
|
||||
var _ = Describe("NetworkConfFromBytes", func() {
|
||||
Describe("Version selection", func() {
|
||||
makeConfig := func(versions ...string) []byte {
|
||||
// ugly fake json encoding, but whatever
|
||||
|
@ -516,36 +725,36 @@ var _ = Describe("ConfListFromBytes", func() {
|
|||
return []byte(fmt.Sprintf(`{"name": "test", "cniVersions": [%s], "plugins": [{"type": "foo"}]}`, strings.Join(vs, ",")))
|
||||
}
|
||||
It("correctly selects the maximum version", func() {
|
||||
conf, err := libcni.ConfListFromBytes(makeConfig("1.1.0", "0.4.0", "1.0.0"))
|
||||
conf, err := libcni.NetworkConfFromBytes(makeConfig("1.1.0", "0.4.0", "1.0.0"))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(conf.CNIVersion).To(Equal("1.1.0"))
|
||||
})
|
||||
|
||||
It("selects the highest version supported by libcni", func() {
|
||||
conf, err := libcni.ConfListFromBytes(makeConfig("99.0.0", "1.1.0", "0.4.0", "1.0.0"))
|
||||
conf, err := libcni.NetworkConfFromBytes(makeConfig("99.0.0", "1.1.0", "0.4.0", "1.0.0"))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(conf.CNIVersion).To(Equal("1.1.0"))
|
||||
})
|
||||
|
||||
It("fails when invalid versions are specified", func() {
|
||||
_, err := libcni.ConfListFromBytes(makeConfig("1.1.0", "0.4.0", "1.0.f"))
|
||||
_, err := libcni.NetworkConfFromBytes(makeConfig("1.1.0", "0.4.0", "1.0.f"))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("falls back to cniVersion", func() {
|
||||
conf, err := libcni.ConfListFromBytes([]byte(`{"name": "test", "cniVersion": "1.2.3", "plugins": [{"type": "foo"}]}`))
|
||||
conf, err := libcni.NetworkConfFromBytes([]byte(`{"name": "test", "cniVersion": "1.2.3", "plugins": [{"type": "foo"}]}`))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(conf.CNIVersion).To(Equal("1.2.3"))
|
||||
})
|
||||
|
||||
It("merges cniVersions and cniVersion", func() {
|
||||
conf, err := libcni.ConfListFromBytes([]byte(`{"name": "test", "cniVersion": "1.0.0", "cniVersions": ["0.1.0", "0.4.0"], "plugins": [{"type": "foo"}]}`))
|
||||
conf, err := libcni.NetworkConfFromBytes([]byte(`{"name": "test", "cniVersion": "1.0.0", "cniVersions": ["0.1.0", "0.4.0"], "plugins": [{"type": "foo"}]}`))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(conf.CNIVersion).To(Equal("1.0.0"))
|
||||
})
|
||||
|
||||
It("handles an empty cniVersions array", func() {
|
||||
conf, err := libcni.ConfListFromBytes([]byte(`{"name": "test", "cniVersions": [], "plugins": [{"type": "foo"}]}`))
|
||||
conf, err := libcni.NetworkConfFromBytes([]byte(`{"name": "test", "cniVersions": [], "plugins": [{"type": "foo"}]}`))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(conf.CNIVersion).To(Equal(""))
|
||||
})
|
||||
|
@ -553,7 +762,7 @@ var _ = Describe("ConfListFromBytes", func() {
|
|||
})
|
||||
|
||||
var _ = Describe("ConfListFromConf", func() {
|
||||
var testNetConfig *libcni.NetworkConfig
|
||||
var testNetConfig *libcni.PluginConfig
|
||||
|
||||
BeforeEach(func() {
|
||||
pb := []byte(`{"name":"some-plugin","cniVersion":"0.3.1", "type":"foobar"}`)
|
||||
|
@ -575,11 +784,11 @@ var _ = Describe("ConfListFromConf", func() {
|
|||
Expect(ncl).To(Equal(&libcni.NetworkConfigList{
|
||||
Name: "some-plugin",
|
||||
CNIVersion: "0.3.1",
|
||||
Plugins: []*libcni.NetworkConfig{testNetConfig},
|
||||
Plugins: []*libcni.PluginConfig{testNetConfig},
|
||||
}))
|
||||
|
||||
// Test that the json unmarshals to the same data
|
||||
ncl2, err := libcni.ConfListFromBytes(bytes)
|
||||
ncl2, err := libcni.NetworkConfFromBytes(bytes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
ncl2.Bytes = nil
|
||||
ncl2.Plugins[0].Bytes = nil
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Copyright the CNI authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Adapted from errors/join.go from go 1.20
|
||||
// This package can be removed once the toolchain is updated to 1.20
|
||||
|
||||
package libcni
|
||||
|
||||
func joinErrors(errs ...error) error {
|
||||
n := 0
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
n++
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
e := &multiError{
|
||||
errs: make([]error, 0, n),
|
||||
}
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
e.errs = append(e.errs, err)
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
type multiError struct {
|
||||
errs []error
|
||||
}
|
||||
|
||||
func (e *multiError) Error() string {
|
||||
var b []byte
|
||||
for i, err := range e.errs {
|
||||
if i > 0 {
|
||||
b = append(b, '\n')
|
||||
}
|
||||
b = append(b, err.Error()...)
|
||||
}
|
||||
return string(b)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
GOLANGCI_LINT_VERSION="v1.51.2"
|
||||
GOLANGCI_LINT_VERSION="v1.57.1"
|
||||
|
||||
go install "github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}"
|
||||
go install "github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}"
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2022 CNI authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ns
|
||||
|
||||
import "github.com/containernetworking/cni/pkg/types"
|
||||
|
||||
func CheckNetNS(nsPath string) (bool, *types.Error) {
|
||||
return false, nil
|
||||
}
|
|
@ -56,8 +56,12 @@ func (n *IPNet) UnmarshalJSON(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// NetConf describes a network.
|
||||
type NetConf struct {
|
||||
// Use PluginConf instead of NetConf, the NetConf
|
||||
// backwards-compat alias will be removed in a future release.
|
||||
type NetConf = PluginConf
|
||||
|
||||
// PluginConf describes a plugin configuration for a specific network.
|
||||
type PluginConf struct {
|
||||
CNIVersion string `json:"cniVersion,omitempty"`
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
|
@ -83,11 +87,8 @@ type GCAttachment struct {
|
|||
|
||||
// Note: DNS should be omit if DNS is empty but default Marshal function
|
||||
// will output empty structure hence need to write a Marshal function
|
||||
func (n *NetConf) MarshalJSON() ([]byte, error) {
|
||||
// use type alias to escape recursion for json.Marshal() to MarshalJSON()
|
||||
type fixObjType = NetConf
|
||||
|
||||
bytes, err := json.Marshal(fixObjType(*n)) //nolint:all
|
||||
func (n *PluginConf) MarshalJSON() ([]byte, error) {
|
||||
bytes, err := json.Marshal(*n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -117,9 +118,10 @@ func (i *IPAM) IsEmpty() bool {
|
|||
type NetConfList struct {
|
||||
CNIVersion string `json:"cniVersion,omitempty"`
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
DisableCheck bool `json:"disableCheck,omitempty"`
|
||||
Plugins []*NetConf `json:"plugins,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
DisableCheck bool `json:"disableCheck,omitempty"`
|
||||
DisableGC bool `json:"disableGC,omitempty"`
|
||||
Plugins []*PluginConf `json:"plugins,omitempty"`
|
||||
}
|
||||
|
||||
// Result is an interface that provides the result of plugin execution
|
||||
|
@ -227,7 +229,7 @@ func (r *Route) Copy() *Route {
|
|||
}
|
||||
|
||||
// Well known error codes
|
||||
// see https://github.com/containernetworking/cni/blob/main/SPEC.md#well-known-error-codes
|
||||
// see https://github.com/containernetworking/cni/blob/main/SPEC.md#error
|
||||
const (
|
||||
ErrUnknown uint = iota // 0
|
||||
ErrIncompatibleCNIVersion // 1
|
||||
|
@ -239,6 +241,8 @@ const (
|
|||
ErrInvalidNetworkConfig // 7
|
||||
ErrInvalidNetNS // 8
|
||||
ErrTryAgainLater uint = 11
|
||||
ErrPluginNotAvailable uint = 50
|
||||
ErrLimitedConnectivity uint = 51
|
||||
ErrInternal uint = 999
|
||||
)
|
||||
|
||||
|
|
|
@ -142,3 +142,27 @@ func GreaterThanOrEqualTo(version, otherVersion string) (bool, error) {
|
|||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// GreaterThan returns true if the first version is greater than the second
|
||||
func GreaterThan(version, otherVersion string) (bool, error) {
|
||||
firstMajor, firstMinor, firstMicro, err := ParseVersion(version)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
secondMajor, secondMinor, secondMicro, err := ParseVersion(otherVersion)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if firstMajor > secondMajor {
|
||||
return true, nil
|
||||
} else if firstMajor == secondMajor {
|
||||
if firstMinor > secondMinor {
|
||||
return true, nil
|
||||
} else if firstMinor == secondMinor && firstMicro > secondMicro {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ func NewResult(version string, resultBytes []byte) (types.Result, error) {
|
|||
|
||||
// ParsePrevResult parses a prevResult in a NetConf structure and sets
|
||||
// the NetConf's PrevResult member to the parsed Result object.
|
||||
func ParsePrevResult(conf *types.NetConf) error {
|
||||
func ParsePrevResult(conf *types.PluginConf) error {
|
||||
if conf.RawPrevResult == nil {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ var _ = Describe("Version operations", func() {
|
|||
err := json.Unmarshal(rawBytes, &raw)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
conf := &types.NetConf{
|
||||
conf := &types.PluginConf{
|
||||
CNIVersion: "1.0.0",
|
||||
Name: "foobar",
|
||||
Type: "baz",
|
||||
|
@ -94,7 +94,7 @@ var _ = Describe("Version operations", func() {
|
|||
})
|
||||
|
||||
It("fails if the prevResult version is unknown", func() {
|
||||
conf := &types.NetConf{
|
||||
conf := &types.PluginConf{
|
||||
CNIVersion: version.Current(),
|
||||
Name: "foobar",
|
||||
Type: "baz",
|
||||
|
@ -108,7 +108,7 @@ var _ = Describe("Version operations", func() {
|
|||
})
|
||||
|
||||
It("fails if the prevResult version does not match the prevResult version", func() {
|
||||
conf := &types.NetConf{
|
||||
conf := &types.PluginConf{
|
||||
CNIVersion: version.Current(),
|
||||
Name: "foobar",
|
||||
Type: "baz",
|
||||
|
@ -128,7 +128,7 @@ var _ = Describe("Version operations", func() {
|
|||
|
||||
Context("when a prevResult is not available", func() {
|
||||
It("does not fail", func() {
|
||||
conf := &types.NetConf{
|
||||
conf := &types.PluginConf{
|
||||
CNIVersion: version.Current(),
|
||||
Name: "foobar",
|
||||
Type: "baz",
|
||||
|
@ -139,4 +139,22 @@ var _ = Describe("Version operations", func() {
|
|||
Expect(conf.PrevResult).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
Context("version parsing", func() {
|
||||
It("parses versions correctly", func() {
|
||||
v1 := "1.1.0"
|
||||
v2 := "1.1.1"
|
||||
|
||||
check := func(a, b string, want bool) {
|
||||
GinkgoHelper()
|
||||
gt, err := version.GreaterThan(a, b)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(gt).To(Equal(want))
|
||||
}
|
||||
|
||||
check(v1, v2, false)
|
||||
check(v2, v1, true)
|
||||
check(v2, v2, false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module github.com/containernetworking/cni/plugins/debug
|
||||
|
||||
go 1.18
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/containernetworking/cni v1.1.2
|
||||
|
|
|
@ -1,16 +1,26 @@
|
|||
github.com/containernetworking/plugins v1.4.0 h1:+w22VPYgk7nQHw7KT92lsRmuToHvb7wwSv9iTbXzzic=
|
||||
github.com/containernetworking/plugins v1.4.0/go.mod h1:UYhcOyjefnrQvKvmmyEKsUA+M9Nfn7tqULPpH0Pkcj0=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBxH5Pj7KeFK5l+Y3FsgT8keqKtk=
|
||||
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
|
||||
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
|
||||
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -36,7 +36,7 @@ import (
|
|||
)
|
||||
|
||||
type NetConf struct {
|
||||
types.NetConf
|
||||
types.PluginConf
|
||||
DebugFile string `json:"debugFile"`
|
||||
CommandLog string `json:"commandLog"`
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func loadConf(bytes []byte) (*NetConf, error) {
|
|||
if err := json.Unmarshal(bytes, n); err != nil {
|
||||
return nil, fmt.Errorf("failed to load netconf: %w %q", err, string(bytes))
|
||||
}
|
||||
if err := version.ParsePrevResult(&n.NetConf); err != nil {
|
||||
if err := version.ParsePrevResult(&n.PluginConf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n, nil
|
||||
|
|
Loading…
Reference in New Issue