Merge pull request #267 from rosenhouse/version-cmd
Adds VERSION command
This commit is contained in:
commit
349d66d51c
@ -22,9 +22,7 @@ Other sysctls can be modified as long as they belong to the network namespace (`
|
|||||||
|
|
||||||
A successful result would simply be:
|
A successful result would simply be:
|
||||||
```
|
```
|
||||||
{
|
{ }
|
||||||
"cniVersion": "0.1.0"
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Network sysctls documentation
|
## Network sysctls documentation
|
||||||
|
18
SPEC.md
18
SPEC.md
@ -62,10 +62,14 @@ The operations that the CNI plugin needs to support are:
|
|||||||
- **Extra arguments**, as defined above.
|
- **Extra arguments**, as defined above.
|
||||||
- **Name of the interface inside the container**, as defined above.
|
- **Name of the interface inside the container**, as defined above.
|
||||||
|
|
||||||
|
- Report version
|
||||||
|
- Parameters: NONE.
|
||||||
|
- Result:
|
||||||
|
- The version of the CNI spec implemented by the plugin: `{ "cniVersion": "0.2.0" }`
|
||||||
|
|
||||||
The executable command-line API uses the type of network (see [Network Configuration](#network-configuration) below) as the name of the executable to invoke.
|
The executable command-line API uses the type of network (see [Network Configuration](#network-configuration) below) as the name of the executable to invoke.
|
||||||
It will then look for this executable in a list of predefined directories. Once found, it will invoke the executable using the following environment variables for argument passing:
|
It will then look for this executable in a list of predefined directories. Once found, it will invoke the executable using the following environment variables for argument passing:
|
||||||
- `CNI_VERSION`: [Semantic Version 2.0](http://semver.org) of CNI specification. This effectively versions the CNI_XXX environment variables.
|
- `CNI_COMMAND`: indicates the desired operation; `ADD`, `DEL` or `VERSION`.
|
||||||
- `CNI_COMMAND`: indicates the desired operation; either `ADD` or `DEL`
|
|
||||||
- `CNI_CONTAINERID`: Container ID
|
- `CNI_CONTAINERID`: Container ID
|
||||||
- `CNI_NETNS`: Path to network namespace file
|
- `CNI_NETNS`: Path to network namespace file
|
||||||
- `CNI_IFNAME`: Interface name to set up
|
- `CNI_IFNAME`: Interface name to set up
|
||||||
@ -81,7 +85,7 @@ Success is indicated by a return code of zero and the following JSON printed to
|
|||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"cniVersion": "0.1.0",
|
"cniVersion": "0.2.0",
|
||||||
"ip4": {
|
"ip4": {
|
||||||
"ip": <ipv4-and-subnet-in-CIDR>,
|
"ip": <ipv4-and-subnet-in-CIDR>,
|
||||||
"gateway": <ipv4-of-the-gateway>, (optional)
|
"gateway": <ipv4-of-the-gateway>, (optional)
|
||||||
@ -110,7 +114,7 @@ Examples include generating an `/etc/resolv.conf` file to be injected into the c
|
|||||||
Errors are indicated by a non-zero return code and the following JSON being printed to stdout:
|
Errors are indicated by a non-zero return code and the following JSON being printed to stdout:
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"cniVersion": "0.1.0",
|
"cniVersion": "0.2.0",
|
||||||
"code": <numeric-error-code>,
|
"code": <numeric-error-code>,
|
||||||
"msg": <short-error-message>,
|
"msg": <short-error-message>,
|
||||||
"details": <long-error-message> (optional)
|
"details": <long-error-message> (optional)
|
||||||
@ -147,7 +151,7 @@ Plugins may define additional fields that they accept and may generate an error
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"cniVersion": "0.1.0",
|
"cniVersion": "0.2.0",
|
||||||
"name": "dbnet",
|
"name": "dbnet",
|
||||||
"type": "bridge",
|
"type": "bridge",
|
||||||
// type (plugin) specific
|
// type (plugin) specific
|
||||||
@ -166,7 +170,7 @@ Plugins may define additional fields that they accept and may generate an error
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"cniVersion": "0.1.0",
|
"cniVersion": "0.2.0",
|
||||||
"name": "pci",
|
"name": "pci",
|
||||||
"type": "ovs",
|
"type": "ovs",
|
||||||
// type (plugin) specific
|
// type (plugin) specific
|
||||||
@ -216,7 +220,7 @@ Success is indicated by a zero return code and the following JSON being printed
|
|||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"cniVersion": "0.1.0",
|
"cniVersion": "0.2.0",
|
||||||
"ip4": {
|
"ip4": {
|
||||||
"ip": <ipv4-and-subnet-in-CIDR>,
|
"ip": <ipv4-and-subnet-in-CIDR>,
|
||||||
"gateway": <ipv4-of-the-gateway>, (optional)
|
"gateway": <ipv4-of-the-gateway>, (optional)
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdArgs captures all the arguments passed in to the plugin
|
// CmdArgs captures all the arguments passed in to the plugin
|
||||||
@ -40,7 +41,9 @@ type CmdArgs struct {
|
|||||||
type dispatcher struct {
|
type dispatcher struct {
|
||||||
Getenv func(string) string
|
Getenv func(string) string
|
||||||
Stdin io.Reader
|
Stdin io.Reader
|
||||||
|
Stdout io.Writer
|
||||||
Stderr io.Writer
|
Stderr io.Writer
|
||||||
|
Versioner version.PluginVersioner
|
||||||
}
|
}
|
||||||
|
|
||||||
type reqForCmdEntry map[string]bool
|
type reqForCmdEntry map[string]bool
|
||||||
@ -154,6 +157,9 @@ func (t *dispatcher) pluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error) *types.Er
|
|||||||
case "DEL":
|
case "DEL":
|
||||||
err = cmdDel(cmdArgs)
|
err = cmdDel(cmdArgs)
|
||||||
|
|
||||||
|
case "VERSION":
|
||||||
|
err = t.Versioner.Encode(t.Stdout)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return createTypedError("unknown CNI_COMMAND: %v", cmd)
|
return createTypedError("unknown CNI_COMMAND: %v", cmd)
|
||||||
}
|
}
|
||||||
@ -174,7 +180,9 @@ func PluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error) {
|
|||||||
caller := dispatcher{
|
caller := dispatcher{
|
||||||
Getenv: os.Getenv,
|
Getenv: os.Getenv,
|
||||||
Stdin: os.Stdin,
|
Stdin: os.Stdin,
|
||||||
|
Stdout: os.Stdout,
|
||||||
Stderr: os.Stderr,
|
Stderr: os.Stderr,
|
||||||
|
Versioner: version.DefaultPluginVersioner,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := caller.pluginMain(cmdAdd, cmdDel)
|
err := caller.pluginMain(cmdAdd, cmdDel)
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/testutils"
|
"github.com/containernetworking/cni/pkg/testutils"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
@ -48,7 +49,7 @@ var _ = Describe("dispatching to the correct callback", func() {
|
|||||||
var (
|
var (
|
||||||
environment map[string]string
|
environment map[string]string
|
||||||
stdin io.Reader
|
stdin io.Reader
|
||||||
stderr *bytes.Buffer
|
stdout, stderr *bytes.Buffer
|
||||||
cmdAdd, cmdDel *fakeCmd
|
cmdAdd, cmdDel *fakeCmd
|
||||||
dispatch *dispatcher
|
dispatch *dispatcher
|
||||||
expectedCmdArgs *CmdArgs
|
expectedCmdArgs *CmdArgs
|
||||||
@ -64,11 +65,15 @@ var _ = Describe("dispatching to the correct callback", func() {
|
|||||||
"CNI_PATH": "/some/cni/path",
|
"CNI_PATH": "/some/cni/path",
|
||||||
}
|
}
|
||||||
stdin = strings.NewReader(`{ "some": "config" }`)
|
stdin = strings.NewReader(`{ "some": "config" }`)
|
||||||
|
stdout = &bytes.Buffer{}
|
||||||
stderr = &bytes.Buffer{}
|
stderr = &bytes.Buffer{}
|
||||||
|
versioner := &version.BasicVersioner{CNIVersion: "9.8.7"}
|
||||||
dispatch = &dispatcher{
|
dispatch = &dispatcher{
|
||||||
Getenv: func(key string) string { return environment[key] },
|
Getenv: func(key string) string { return environment[key] },
|
||||||
Stdin: stdin,
|
Stdin: stdin,
|
||||||
|
Stdout: stdout,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
|
Versioner: versioner,
|
||||||
}
|
}
|
||||||
cmdAdd = &fakeCmd{}
|
cmdAdd = &fakeCmd{}
|
||||||
cmdDel = &fakeCmd{}
|
cmdDel = &fakeCmd{}
|
||||||
@ -171,6 +176,36 @@ var _ = Describe("dispatching to the correct callback", func() {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("when the CNI_COMMAND is VERSION", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
environment["CNI_COMMAND"] = "VERSION"
|
||||||
|
})
|
||||||
|
|
||||||
|
It("prints the version to stdout", func() {
|
||||||
|
err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(stdout).To(MatchJSON(`{ "cniVersion": "9.8.7" }`))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("does not call cmdAdd or cmdDel", func() {
|
||||||
|
err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(cmdAdd.CallCount).To(Equal(0))
|
||||||
|
Expect(cmdDel.CallCount).To(Equal(0))
|
||||||
|
})
|
||||||
|
|
||||||
|
DescribeTable("VERSION does not need the usual env vars", envVarChecker,
|
||||||
|
Entry("command", "CNI_COMMAND", true),
|
||||||
|
Entry("container id", "CNI_CONTAINER_ID", false),
|
||||||
|
Entry("net ns", "CNI_NETNS", false),
|
||||||
|
Entry("if name", "CNI_IFNAME", false),
|
||||||
|
Entry("args", "CNI_ARGS", false),
|
||||||
|
Entry("path", "CNI_PATH", false),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
Context("when the CNI_COMMAND is unrecognized", func() {
|
Context("when the CNI_COMMAND is unrecognized", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
environment["CNI_COMMAND"] = "NOPE"
|
environment["CNI_COMMAND"] = "NOPE"
|
||||||
|
42
pkg/version/version.go
Normal file
42
pkg/version/version.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2016 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 version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A PluginVersioner can encode information about its version
|
||||||
|
type PluginVersioner interface {
|
||||||
|
Encode(io.Writer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// BasicVersioner is a PluginVersioner which reports a single cniVersion string
|
||||||
|
type BasicVersioner struct {
|
||||||
|
CNIVersion string `json:"cniVersion"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *BasicVersioner) Encode(w io.Writer) error {
|
||||||
|
return json.NewEncoder(w).Encode(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current reports the version of the CNI spec implemented by this library
|
||||||
|
func Current() string {
|
||||||
|
return "0.2.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultPluginVersioner reports the Current library spec version as the cniVersion
|
||||||
|
var DefaultPluginVersioner = &BasicVersioner{CNIVersion: Current()}
|
Loading…
x
Reference in New Issue
Block a user