spec, skel: Make the container ID required and unique.
authorCasey Callendrello <casey.callendrello@coreos.com>
Fri, 22 Sep 2017 12:48:55 +0000 (14:48 +0200)
committerCasey Callendrello <casey.callendrello@coreos.com>
Fri, 20 Oct 2017 12:26:18 +0000 (14:26 +0200)
Previously, the spec did not require the container id to be set.
However, almost every plugin relies on it being unique, including the
CNI-maintained plugins. So, change the spec to require the use of
containerid and that plugins should treat it as a primary key.

SPEC.md
pkg/invoke/delegate_test.go
pkg/skel/skel.go
pkg/skel/skel_test.go

diff --git a/SPEC.md b/SPEC.md
index c61bcae..d583ef6 100644 (file)
--- a/SPEC.md
+++ b/SPEC.md
@@ -47,12 +47,14 @@ https://docs.google.com/a/coreos.com/document/d/1CTAL4gwqRofjxyp4tTkbgHtAwb2YCcP
 - Upon completion of the container lifecycle, the runtime must execute the plugins in reverse order (relative to the order in which they were executed to add the container) to disconnect the container from the networks.
 - The container runtime must not invoke parallel operations for the same container, but is allowed to invoke parallel operations for different containers.
 - The container runtime must order ADD and DEL operations for a container, such that ADD is always followed by a corresponding DEL. DEL may be followed by additional DELs, however, and plugins should handle multiple DELs permissively (i.e. plugin DEL should be idempotent).
+- A container must be uniquely identified by a ContainerID. Plugins that store state should do so using a primary key of `(network name, container id)`.
+- A runtime must not call ADD twice (without a corresponding DEL) for the same `(network name, container id)`. In other words, a given container ID must be added to a specific network exactly once.
 
 ## CNI Plugin
 
 ### Overview
 
-Each CNI plugin must be implemented as an executable that is invoked by the container management system (e.g. rkt or Docker).
+Each CNI plugin must be implemented as an executable that is invoked by the container management system (e.g. rkt or Kubernetes).
 
 A CNI plugin is responsible for inserting a network interface into the container network namespace (e.g. one end of a veth pair) and making any necessary changes on the host (e.g. attaching the other end of the veth into a bridge).
 It should then assign the IP to the interface and setup the routes consistent with the IP Address Management section by invoking appropriate IPAM plugin.
@@ -61,11 +63,10 @@ It should then assign the IP to the interface and setup the routes consistent wi
 
 The operations that CNI plugins must support are:
 
-
 - Add container to network
   - Parameters:
     - **Version**. The version of CNI spec that the caller is using (container management system or the invoking plugin).
-    - **Container ID**. This is optional but recommended, and should be unique across an administrative domain while the container is live (it may be reused in the future). For example, an environment with an IPAM system may require that each container is allocated a unique ID and that each IP allocation can thus be correlated back to a particular container. As another example, in appc implementations this would be the _pod ID_.
+    - **Container ID**. A unique plaintext identifier for a container, allocated by the runtime. Must not be empty.
     - **Network namespace path**. This represents the path to the network namespace to be added, i.e. /proc/[pid]/ns/net or a bind-mount/link to it.
     - **Network configuration**. This is a JSON document describing a network to which a container can be joined. The schema is described below.
     - **Extra arguments**. This provides an alternative mechanism to allow simple configuration of CNI plugins on a per-container basis.
@@ -83,6 +84,8 @@ The operations that CNI plugins must support are:
     - **Network configuration**, as defined above.
     - **Extra arguments**, as defined above.
     - **Name of the interface inside the container**, as defined above.
+ - All parameters should be the same as those passed to the corresponding add operation.
+ - A delete operation should release all resources held by the supplied containerid in the configured network.
 
 - Report version
   - Parameters: NONE.
index 3d87ec7..d00d4ae 100644 (file)
@@ -71,6 +71,7 @@ var _ = Describe("Delegate", func() {
                os.Setenv("CNI_PATH", filepath.Dir(pathToPlugin))
                os.Setenv("CNI_NETNS", "/tmp/some/netns/path")
                os.Setenv("CNI_IFNAME", "eth7")
+               os.Setenv("CNI_CONTAINERID", "container")
        })
 
        AfterEach(func() {
index 69c58e0..71ae559 100644 (file)
@@ -71,8 +71,8 @@ func (t *dispatcher) getCmdArgsFromEnv() (string, *CmdArgs, error) {
                        "CNI_CONTAINERID",
                        &contID,
                        reqForCmdEntry{
-                               "ADD": false,
-                               "DEL": false,
+                               "ADD": true,
+                               "DEL": true,
                        },
                },
                {
index 2b4d66d..ef501c0 100644 (file)
@@ -120,7 +120,7 @@ var _ = Describe("dispatching to the correct callback", func() {
 
                DescribeTable("required / optional env vars", envVarChecker,
                        Entry("command", "CNI_COMMAND", true),
-                       Entry("container id", "CNI_CONTAINERID", false),
+                       Entry("container id", "CNI_CONTAINERID", true),
                        Entry("net ns", "CNI_NETNS", true),
                        Entry("if name", "CNI_IFNAME", true),
                        Entry("args", "CNI_ARGS", false),
@@ -207,7 +207,7 @@ var _ = Describe("dispatching to the correct callback", func() {
 
                DescribeTable("required / optional env vars", envVarChecker,
                        Entry("command", "CNI_COMMAND", true),
-                       Entry("container id", "CNI_CONTAINERID", false),
+                       Entry("container id", "CNI_CONTAINERID", true),
                        Entry("net ns", "CNI_NETNS", false),
                        Entry("if name", "CNI_IFNAME", true),
                        Entry("args", "CNI_ARGS", false),