github.com/john-lin/cni@v0.6.0-rc1.0.20170712150331-b69e640cc0e2/Documentation/spec-upgrades.md (about)

     1  # How to upgrade to CNI Specification v0.3.1
     2  
     3  The 0.3.0 specification contained a small error. The Result structure's `ip` field should have been renamed to `ips` to be consistent with the IPAM result structure definition; this rename was missed when updating the Result to accommodate multiple IP addresses and interfaces. All first-party CNI plugins (bridge, host-local, etc) were updated to use `ips` (and thus be inconsistent with the 0.3.0 specification) and most other plugins have not been updated to the 0.3.0 specification yet, so few (if any) users should be impacted by this change.
     4  
     5  The 0.3.1 specification corrects the Result structure to use the `ips` field name as originally intended.  This is the only change between 0.3.0 and 0.3.1.
     6  
     7  # How to upgrade to CNI Specification v0.3.0
     8  
     9  Version 0.3.0 of the [CNI Specification](../SPEC.md) provides rich information
    10  about container network configuration, including details of network interfaces
    11  and support for multiple IP addresses.
    12  
    13  To support this new data, the specification changed in a couple significant
    14  ways that will impact CNI users, plugin authors, and runtime authors.
    15  
    16  This document provides guidance for how to upgrade:
    17  
    18  - [For CNI Users](#for-cni-users)
    19  - [For Plugin Authors](#for-plugin-authors)
    20  - [For Runtime Authors](#for-runtime-authors)
    21  
    22  **Note**: the CNI Spec is versioned independently from the GitHub releases
    23  for this repo.  For example, Release v0.4.0 supports Spec version v0.2.0,
    24  and Release v0.5.0 supports Spec v0.3.0.
    25  
    26  ----
    27  
    28  ## For CNI Users
    29  If you maintain CNI configuration files for a container runtime that uses CNI,
    30  ensure that the configuration files specify a `cniVersion` field and that the
    31  version there is supported by your container runtime and CNI plugins.
    32  Configuration files without a version field should be given version 0.2.0. 
    33  The CNI spec includes example configuration files for 
    34  [single plugins](https://github.com/containernetworking/cni/blob/master/SPEC.md#example-configurations)
    35  and for [lists of chained plugins](https://github.com/containernetworking/cni/blob/master/SPEC.md#example-configurations).
    36  
    37  Consult the documentation for your runtime and plugins to determine what
    38  CNI spec versions they support. Test any plugin upgrades before deploying to 
    39  production. You may find [cnitool](https://github.com/containernetworking/cni/tree/master/cnitool)
    40  useful. Specifically, your configuration version should be the lowest common
    41  version supported by your plugins.
    42  
    43  ## For Plugin Authors
    44  This section provides guidance for upgrading plugins to CNI Spec Version 0.3.0.
    45  
    46  ### General guidance for all plugins (language agnostic)
    47  To provide the smoothest upgrade path, **existing plugins should support
    48  multiple versions of the CNI spec**.  In particular, plugins with existing
    49  installed bases should add support for CNI spec version 0.3.0 while maintaining
    50  compatibility with older versions.
    51  
    52  To do this, two changes are required.  First, a plugin should advertise which
    53  CNI spec versions it supports.  It does this by responding to the `VERSION`
    54  command with the following JSON data:
    55  
    56  ```json
    57  {
    58    "cniVersion": "0.3.0",
    59    "supportedVersions": [ "0.1.0", "0.2.0", "0.3.0" ]
    60  }
    61  ```
    62  
    63  Second, for the `ADD` command, a plugin must respect the `cniVersion` field
    64  provided in the [network configuration JSON](https://github.com/containernetworking/cni/blob/master/SPEC.md#network-configuration). 
    65  That field is a request for the plugin to return results of a particular format:
    66  
    67  - If the `cniVersion` field is not present, then spec v0.2.0 should be assumed
    68  	and v0.2.0 format result JSON returned.
    69  
    70  - If the plugin doesn't support the version, the plugin must error.
    71  
    72  - Otherwise, the plugin must return a [CNI Result](https://github.com/containernetworking/cni/blob/master/SPEC.md#result)
    73  	in the format requested.
    74  
    75  Result formats for older CNI spec versions are available in the
    76  [git history for SPEC.md](https://github.com/containernetworking/cni/commits/master/SPEC.md).
    77  
    78  For example, suppose a plugin, via its `VERSION` response, advertises CNI specification
    79  support for v0.2.0 and v0.3.0.  When it receives `cniVersion` key of `0.2.0`,
    80  the plugin must return result JSON conforming to CNI spec version 0.2.0.
    81  
    82  ### Specific guidance for plugins written in Go
    83  Plugins written in Go may leverage the Go language packages in this repository
    84  to ease the process of upgrading and supporting multiple versions.  CNI 
    85  [Library and Plugins Release v0.5.0](https://github.com/containernetworking/cni/releases)
    86  includes important changes to the Golang APIs.  Plugins using these APIs will
    87  require some changes now, but should more-easily handle spec changes and
    88  new features going forward.
    89  
    90  For plugin authors, the biggest change is that `types.Result` is now an
    91  interface implemented by concrete struct types in the `types/current` and
    92  `types/020` subpackages.
    93  
    94  Internally, plugins should use the `types/current` structs, and convert
    95  to or from specific versions when required.  A typical plugin will only need
    96  to do a single conversion.  That is when it is about to complete and needs to
    97  print the result JSON in the correct format to stdout.  The library
    98  function `types.PrintResult()` simplifies this by converting and printing in
    99  a single call.
   100  
   101  Additionally, the plugin should advertise which CNI Spec versions it supports
   102  via the 3rd argument to `skel.PluginMain()`.
   103  
   104  Here is some example code
   105  
   106  ```go
   107  import (
   108  	 "github.com/containernetworking/cni/pkg/skel"
   109  	 "github.com/containernetworking/cni/pkg/types"
   110  	 "github.com/containernetworking/cni/pkg/types/current"
   111  	 "github.com/containernetworking/cni/pkg/version"
   112  )
   113  
   114  func cmdAdd(args *skel.CmdArgs) error {
   115  	// determine spec version to use
   116  	var netConf struct {
   117  		types.NetConf
   118  		// other plugin-specific configuration goes here
   119  	}
   120  	err := json.Unmarshal(args.StdinData, &netConf)
   121  	cniVersion := netConf.CNIVersion
   122  
   123  	// plugin does its work...
   124  	//   set up interfaces
   125  	//   assign addresses, etc
   126  	
   127  	// construct the result
   128  	result := &current.Result{
   129  		Interfaces: []*current.Interface{ ... },
   130  		IPs: []*current.IPs{ ... },
   131  		...
   132  	}
   133  	
   134  	// print result to stdout, in the format defined by the requested cniVersion
   135  	return types.PrintResult(result, cniVersion)
   136  }
   137  
   138  func main() {
   139  	skel.PluginMain(cmdAdd, cmdDel, version.PluginSupports("0.1.0", "0.2.0", "0.3.0"))
   140  }
   141  ```
   142  
   143  Alternately, to use the result from a delegated IPAM plugin, the `result`
   144  value might be formed like this:
   145  
   146  ```go
   147  ipamResult, err := ipam.ExecAdd(netConf.IPAM.Type, args.StdinData)
   148  result, err := current.NewResultFromResult(ipamResult)
   149  ```
   150  
   151  Other examples of spec v0.3.0-compatible plugins are the
   152  [main plugins in this repo](https://github.com/containernetworking/cni/tree/master/plugins/main)
   153  
   154  
   155  ## For Runtime Authors
   156  
   157  This section provides guidance for upgrading container runtimes to support
   158  CNI Spec Version 0.3.0.
   159  
   160  ### General guidance for all runtimes (language agnostic)
   161  
   162  #### Support multiple CNI spec versions
   163  To provide the smoothest upgrade path and support the broadest range of CNI
   164  plugins, **container runtimes should support multiple versions of the CNI spec**.
   165  In particular, runtimes with existing installed bases should add support for CNI
   166  spec version 0.3.0 while maintaining compatibility with older versions.
   167  
   168  To support multiple versions of the CNI spec, runtimes should be able to
   169  call both new and legacy plugins, and handle the results from either.
   170  
   171  When calling a plugin, the runtime must request that the plugin respond in a
   172  particular format by specifying the `cniVersion` field in the
   173  [Network Configuration](https://github.com/containernetworking/cni/blob/master/SPEC.md#network-configuration)
   174  JSON block.  The plugin will then respond with
   175  a [Result](https://github.com/containernetworking/cni/blob/master/SPEC.md#result)
   176  in the format defined by that CNI spec version, and the runtime must parse
   177  and handle this result.
   178  
   179  #### Handle errors due to version incompatibility
   180  Plugins may respond with error indicating that they don't support the requested
   181  CNI version (see [Well-known Error Codes](https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes)),
   182  e.g.
   183  ```json
   184  {
   185    "cniVersion": "0.2.0",
   186    "code": 1,
   187    "msg": "CNI version not supported"
   188  }
   189  ```
   190  In that case, the runtime may retry with a lower CNI spec version, or take
   191  some other action.
   192  
   193  #### (optional) Discover plugin version support
   194  Runtimes may discover which CNI spec versions are supported by a plugin, by
   195  calling the plugin with the `VERSION` command.  The `VERSION` command was
   196  added in CNI spec v0.2.0, so older plugins may not respect it.  In the absence
   197  of a successful response to `VERSION`, assume that the plugin only supports
   198  CNI spec v0.1.0.
   199  
   200  #### Handle missing data in v0.3.0 results
   201  The Result for the `ADD` command in CNI spec version 0.3.0 includes a new field
   202  `interfaces`.  An IP address in the `ip` field may describe which interface
   203  it is assigned to, by placing a numeric index in the `interface` subfield.
   204  
   205  However, some plugins which are v0.3.0 compatible may nonetheless omit the
   206  `interfaces` field and/or set the `interface` index value to `-1`.  Runtimes
   207  should gracefully handle this situation, unless they have good reason to rely
   208  on the existence of the interface data.  In that case, provide the user an
   209  error message that helps diagnose the issue.
   210  
   211  ### Specific guidance for container runtimes written in Go
   212  Container runtimes written in Go may leverage the Go language packages in this
   213  repository to ease the process of upgrading and supporting multiple versions.
   214  CNI [Library and Plugins Release v0.5.0](https://github.com/containernetworking/cni/releases)
   215  includes important changes to the Golang APIs.  Runtimes using these APIs will
   216  require some changes now, but should more-easily handle spec changes and
   217  new features going forward.
   218  
   219  For runtimes, the biggest changes to the Go libraries are in the `types` package.
   220  It has been refactored to make working with versioned results simpler. The top-level 
   221  `types.Result` is now an opaque interface instead of a struct, and APIs exposed by
   222  other packages, such as the high-level `libcni` package, have been updated to use 
   223  this interface.  Concrete types are now per-version subpackages. The `types/current`
   224  subpackage contains the latest (spec v0.3.0) types.
   225  
   226  When up-converting older result types to spec v0.3.0, fields new in
   227  spec v0.3.0 (like `interfaces`) may be empty.  Conversely, when
   228  down-converting v0.3.0 results to an older version, any data in those fields
   229  will be lost.
   230  
   231  | From   | 0.1 | 0.2 | 0.3 |
   232  |--------|-----|-----|-----|
   233  | To 0.1 |  ✔  |  ✔  |  x  |
   234  | To 0.2 |  ✔  |  ✔  |  x  |
   235  | To 0.3 |  ✴  |  ✴  |  ✔  |
   236  
   237  
   238  Key:
   239  > ✔ : lossless conversion <br>
   240  > ✴ : higher-version output may have empty fields <br>
   241  > x : lower-version output is missing some data <br>
   242  
   243  
   244  
   245  A container runtime should use `current.NewResultFromResult()` to convert the
   246  opaque  `types.Result` to a concrete `current.Result` struct.  It may then
   247  work with the fields exposed by that struct:
   248  
   249  ```go
   250  // runtime invokes the plugin to get the opaque types.Result
   251  // this may conform to any CNI spec version
   252  resultInterface, err := libcni.AddNetwork(netConf, runtimeConf)
   253  
   254  // upconvert result to the current 0.3.0 spec
   255  result, err := current.NewResultFromResult(resultInterface)
   256  
   257  // use the result fields ....
   258  for _, ip := range result.IPs { ... }
   259  ```