From 328ea56e7530c057d54d57e3b719bc643227288c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 26 Feb 2017 13:26:14 -0800 Subject: [PATCH] docs: CNI versioning for 0.3.0 upgrade --- Documentation/spec-upgrades.md | 101 +++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/spec-upgrades.md diff --git a/Documentation/spec-upgrades.md b/Documentation/spec-upgrades.md new file mode 100644 index 00000000..b9ac77ec --- /dev/null +++ b/Documentation/spec-upgrades.md @@ -0,0 +1,101 @@ +# CNI Plugin Versions, Compatibility, and Writing Plugins + +## Specification Changes between CNI Specification Versions 0.2.0 and +0.3.0 + +Plugins which conform to the CNI 0.3.0 specification may elect to +return more expressive IPAM JSON that is not compatible with earlier +specification versions. This requires updates to plugins that wish to +conform to the 0.3.0 specification. It **does not** require updates to +plugins that wish to only implement the 0.2.0 and earlier +specifications. + +## Multi-version Compatible Plugins + +Plugins can also choose to support multiple CNI versions. The plugin is +expected to return IPAM output conforming to the CNI specification +version passed in the plugin's configuration on stdin in the +`cniVersion` key. If that key is not present, then CNI specification +version 0.2.0 should be assumed and 0.2.0 conforming JSON returned. +Plugins should return all CNI specification versions they are +compatible with when given the `VERSION` command, so runtimes can +determine each plugins capabilities. + +For example, if the plugin advertises only CNI specification version +0.2.0 support and receives a `cniVersion` key of "0.3.0" the plugin +must return an error. If the plugin advertises CNI specification +support for 0.2.0 and 0.3.0, and receives `cniVersion` key of "0.2.0", +the plugin must return IPAM JSON conforming to the CNI specification +version 0.2.0. + +## libcni API and Go Types Changes in 0.3.0 + +With the 0.5.0 CNI reference plugins and libcni release a number of +important changes were made that affect both runtimes and plugin +authors. These changes make it easier to enhance the libcni and plugin +interfaces going forward. The largest changes are to the `types` +package, which now contains multiple versions of libcni types. The +`current` package contains the latest types, while types compatible +with previous libcni releases will be placed into versioned packages +like `types020` (representing the libcni types that conform to the CNI +specification version 0.2.0). + +The `Result` type is now an interface instead of a plain struct. The +interface has new functions to convert the Result structure between +different versions of the libcni types. Plugins and consumers of libcni +should generally be written to use the Go types of the latest libcni +release, and convert between the latest libcni types and the CNI +specification type they are passed in the `cniVersion` key of plugin +configuration. + +### Plugins + +For example, say your plugins supports both CNI specification version +0.2.0 and 0.3.0. Your plugin receives configuration with a `cniVersion` +key of "0.2.0". This means your plugin should return an IPAM structure +conforming to the CNI specification version 0.2.0. The easiest way to +code your plugin is to always use the most current libcni Result type +(from the `current` package) and then immediately before exiting, +convert that result to the requested CNI specification version result +(eg, `types020`) and print it to stdout. + +``` +import "github.com/containernetworking/cni/pkg/types" +import "github.com/containernetworking/cni/pkg/types/current" + +result := ¤t.Result{} +<<< populate result here >>> +return types.PrintResult(result, << CNI version from stdin net +config>>) +``` + +or if your plugin internally runs IPAM and needs to process the result: + +``` +import "github.com/containernetworking/cni/pkg/types" +import "github.com/containernetworking/cni/pkg/types/current" + +ipamResult, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData) +result, err := current.NewResultFromResult(ipamResult) +<<< manipulate result here >>> +return types.PrintResult(result, << CNI version from stdin net +config>>) +``` + +### Runtimes + +Since libcni functions like AddNetwork() now return a Result interface +rather than a plain structure, only a single additional step is +required to convert that object to a structure you can manipulate +internally. Runtimes should code to the most current Go types provided +by the libcni they vendor into their sources, and can convert from +whatever IPAM result version the plugin provides to the most current +version like so: + +``` +resultInterface, err := cninet.AddNetwork(netconf, rt) +<<< resultInterface could wrap an object of any CNI specification +version >>> +realResult := current.NewResultFromResult(resultInterface) +<<< realResult is a struct, not an interface >>> +```