sample: create sample plugin
This commit is contained in:
parent
fb4a7f477b
commit
d62b9a0584
7
plugins/sample/README.md
Normal file
7
plugins/sample/README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Sample CNI plugin
|
||||||
|
|
||||||
|
This is an example of a sample chained plugin. It includes solutions for some
|
||||||
|
of the more subtle cases that can be experienced with multi-version chained
|
||||||
|
plugins.
|
||||||
|
|
||||||
|
To use it, just add your code to the cmdAdd and cmdDel plugins.
|
139
plugins/sample/main.go
Normal file
139
plugins/sample/main.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// This is a sample chained plugin that supports multiple CNI versions. It
|
||||||
|
// parses prevResult according to the cniVersion
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PluginConf is whatever you expect your configuration json to be. This is whatever
|
||||||
|
// is passed in on stdin. Your plugin may wish to expose its functionality via
|
||||||
|
// runtime args, see CONVENTIONS.md in the CNI spec.
|
||||||
|
type PluginConf struct {
|
||||||
|
types.NetConf // You may wish to not nest this type
|
||||||
|
RuntimeConfig *struct {
|
||||||
|
SampleConfig map[string]interface{} `json:"sample"`
|
||||||
|
} `json:"runtimeConfig"`
|
||||||
|
|
||||||
|
// This is the previous result, when called in the context of a chained
|
||||||
|
// plugin. Because this plugin supports multiple versions, we'll have to
|
||||||
|
// parse this in two passes. If your plugin is not chained, this can be
|
||||||
|
// removed (though you may wish to error if a non-chainable plugin is
|
||||||
|
// chained.
|
||||||
|
// If you need to modify the result before returning it, you will need
|
||||||
|
// to actually convert it to a concrete versioned struct.
|
||||||
|
RawPrevResult *map[string]interface{} `json:"prevResult"`
|
||||||
|
PrevResult *current.Result `json:"-"`
|
||||||
|
|
||||||
|
// Add plugin-specifc flags here
|
||||||
|
MyAwesomeFlag bool `json:"myAwesomeFlag"`
|
||||||
|
AnotherAwesomeArg string `json:"anotherAwesomeArg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseConfig parses the supplied configuration (and prevResult) from stdin.
|
||||||
|
func parseConfig(stdin []byte) (*PluginConf, error) {
|
||||||
|
conf := PluginConf{}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(stdin, &conf); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse network configuration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse previous result. Remove this if your plugin is not chained.
|
||||||
|
if conf.RawPrevResult != nil {
|
||||||
|
resultBytes, err := json.Marshal(conf.RawPrevResult)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not serialize prevResult: %v", err)
|
||||||
|
}
|
||||||
|
res, err := version.NewResult(conf.CNIVersion, resultBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not parse prevResult: %v", err)
|
||||||
|
}
|
||||||
|
conf.RawPrevResult = nil
|
||||||
|
conf.PrevResult, err = current.NewResultFromResult(res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not convert result to current version: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End previous result parsing
|
||||||
|
|
||||||
|
// Do any validation here
|
||||||
|
if conf.AnotherAwesomeArg == "" {
|
||||||
|
return nil, fmt.Errorf("anotherAwesomeArg must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cmdAdd is called for ADD requests
|
||||||
|
func cmdAdd(args *skel.CmdArgs) error {
|
||||||
|
conf, err := parseConfig(args.StdinData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.PrevResult == nil {
|
||||||
|
return fmt.Errorf("must be called as chained plugin")
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is some sample code to generate the list of container-side IPs.
|
||||||
|
// We're casting the prevResult to a 0.3.0 response, which can also include
|
||||||
|
// host-side IPs (but doesn't when converted from a 0.2.0 response).
|
||||||
|
containerIPs := make([]net.IP, 0, len(conf.PrevResult.IPs))
|
||||||
|
if conf.CNIVersion != "0.3.0" {
|
||||||
|
for _, ip := range conf.PrevResult.IPs {
|
||||||
|
containerIPs = append(containerIPs, ip.Address.IP)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, ip := range conf.PrevResult.IPs {
|
||||||
|
intIdx := ip.Interface
|
||||||
|
// Every IP is indexed in to the interfaces array, with "-1" standing
|
||||||
|
// for an unknown interface (which we'll assume to be Container-side
|
||||||
|
// Skip all IPs we know belong to an interface with the wrong name.
|
||||||
|
if intIdx >= 0 && intIdx < len(conf.PrevResult.Interfaces) && conf.PrevResult.Interfaces[intIdx].Name != args.IfName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
containerIPs = append(containerIPs, ip.Address.IP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass through the result for the next plugin
|
||||||
|
return types.PrintResult(conf.PrevResult, conf.CNIVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cmdDel is called for DELETE requests
|
||||||
|
func cmdDel(args *skel.CmdArgs) error {
|
||||||
|
conf, err := parseConfig(args.StdinData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = conf
|
||||||
|
|
||||||
|
// Do your delete here
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
skel.PluginMain(cmdAdd, cmdDel, version.PluginSupports("", "0.1.0", "0.2.0", version.Current()))
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user