Windows Support
Patch for https://github.com/containernetworking/plugins/pull/85
+ Windows cni plugins are added
(*) win-bridge (hostgw)
(*) win-overlay (vxlan)
+ Windows netconf unit test
+ Fix appveyor config to run the test
+ Build release support for windows plugins
Address comments
From:
- https://github.com/containernetworking/plugins/pull/85
- 0049c64e3f
This commit is contained in:
@ -1,11 +0,0 @@
|
||||
plugins/ipam/dhcp
|
||||
plugins/main/bridge
|
||||
plugins/main/host-device
|
||||
plugins/main/ipvlan
|
||||
plugins/main/loopback
|
||||
plugins/main/macvlan
|
||||
plugins/main/ptp
|
||||
plugins/main/vlan
|
||||
plugins/meta/portmap
|
||||
plugins/meta/tuning
|
||||
plugins/meta/bandwidth
|
13
plugins/main/windows/build.sh
Executable file
13
plugins/main/windows/build.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
PLUGINS=$(cat plugins/windows_only.txt)
|
||||
for d in $PLUGINS; do
|
||||
if [ -d "$d" ]; then
|
||||
plugin="$(basename "$d").exe"
|
||||
|
||||
echo " $plugin"
|
||||
CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 \
|
||||
$GO build -o "${PWD}/bin/$plugin" "$@" "$REPO_PATH"/$d
|
||||
fi
|
||||
done
|
25
plugins/main/windows/win-bridge/README.md
Normal file
25
plugins/main/windows/win-bridge/README.md
Normal file
@ -0,0 +1,25 @@
|
||||
# win-bridge plugin
|
||||
|
||||
## Overview
|
||||
|
||||
With win-bridge plugin, all containers (on the same host) are plugged into an L2Bridge network that has one endpoint in the host namespace.
|
||||
|
||||
## Example configuration
|
||||
```
|
||||
{
|
||||
"name": "mynet",
|
||||
"type": "win-bridge",
|
||||
"ipMasqNetwork": "10.244.0.0/16",
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.10.0.0/16"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Network configuration reference
|
||||
|
||||
* `name` (string, required): the name of the network.
|
||||
* `type` (string, required): "win-bridge".
|
||||
* `ipMasqNetwork` (string, optional): setup NAT if not empty.
|
||||
* `ipam` (dictionary, required): IPAM configuration to be used for this network.
|
44
plugins/main/windows/win-bridge/sample.conf
Executable file
44
plugins/main/windows/win-bridge/sample.conf
Executable file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name":"cbr0",
|
||||
"type":"flannel",
|
||||
"delegate":{
|
||||
"type":"win-bridge",
|
||||
"dns":{
|
||||
"nameservers":[
|
||||
"11.0.0.10"
|
||||
],
|
||||
"search":[
|
||||
"svc.cluster.local"
|
||||
]
|
||||
},
|
||||
"policies":[
|
||||
{
|
||||
"name":"EndpointPolicy",
|
||||
"value":{
|
||||
"Type":"OutBoundNAT",
|
||||
"ExceptionList":[
|
||||
"192.168.0.0/16",
|
||||
"11.0.0.0/8",
|
||||
"10.137.196.0/23"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"EndpointPolicy",
|
||||
"value":{
|
||||
"Type":"ROUTE",
|
||||
"DestinationPrefix":"11.0.0.0/8",
|
||||
"NeedEncap":true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"EndpointPolicy",
|
||||
"value":{
|
||||
"Type":"ROUTE",
|
||||
"DestinationPrefix":"10.137.198.27/32",
|
||||
"NeedEncap":true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
151
plugins/main/windows/win-bridge/win-bridge_windows.go
Normal file
151
plugins/main/windows/win-bridge/win-bridge_windows.go
Normal file
@ -0,0 +1,151 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/juju/errors"
|
||||
|
||||
"github.com/Microsoft/hcsshim"
|
||||
"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"
|
||||
"github.com/containernetworking/plugins/pkg/hns"
|
||||
"github.com/containernetworking/plugins/pkg/ipam"
|
||||
)
|
||||
|
||||
type NetConf struct {
|
||||
hns.NetConf
|
||||
|
||||
IPMasqNetwork string `json:"ipMasqNetwork,omitempty"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
// this ensures that main runs only on main thread (thread group leader).
|
||||
// since namespace ops (unshare, setns) are done for a single thread, we
|
||||
// must ensure that the goroutine does not jump from OS thread to thread
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
func loadNetConf(bytes []byte) (*NetConf, string, error) {
|
||||
n := &NetConf{}
|
||||
if err := json.Unmarshal(bytes, n); err != nil {
|
||||
return nil, "", fmt.Errorf("failed to load netconf: %v", err)
|
||||
}
|
||||
return n, n.CNIVersion, nil
|
||||
}
|
||||
|
||||
func cmdAdd(args *skel.CmdArgs) error {
|
||||
n, cniVersion, err := loadNetConf(args.StdinData)
|
||||
if err != nil {
|
||||
return errors.Annotate(err, "error while loadNetConf")
|
||||
}
|
||||
|
||||
networkName := n.Name
|
||||
hnsNetwork, err := hcsshim.GetHNSNetworkByName(networkName)
|
||||
if err != nil {
|
||||
return errors.Annotatef(err, "error while GETHNSNewtorkByName(%s)", networkName)
|
||||
}
|
||||
|
||||
if hnsNetwork == nil {
|
||||
return fmt.Errorf("network %v not found", networkName)
|
||||
}
|
||||
|
||||
if !strings.EqualFold(hnsNetwork.Type, "L2Bridge") {
|
||||
return fmt.Errorf("network %v is of an unexpected type: %v", networkName, hnsNetwork.Type)
|
||||
}
|
||||
|
||||
epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name)
|
||||
|
||||
hnsEndpoint, err := hns.ProvisionEndpoint(epName, hnsNetwork.Id, args.ContainerID, func() (*hcsshim.HNSEndpoint, error) {
|
||||
// run the IPAM plugin and get back the config to apply
|
||||
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "error while ipam.ExecAdd")
|
||||
}
|
||||
|
||||
// Convert whatever the IPAM result was into the current Result type
|
||||
result, err := current.NewResultFromResult(r)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "error while NewResultFromResult")
|
||||
}
|
||||
|
||||
if len(result.IPs) == 0 {
|
||||
return nil, errors.New("IPAM plugin return is missing IP config")
|
||||
}
|
||||
|
||||
// Calculate gateway for bridge network (needs to be x.2)
|
||||
gw := result.IPs[0].Address.IP.Mask(result.IPs[0].Address.Mask)
|
||||
gw[len(gw)-1] += 2
|
||||
|
||||
// NAT based on the the configured cluster network
|
||||
if len(n.IPMasqNetwork) != 0 {
|
||||
n.ApplyOutboundNatPolicy(n.IPMasqNetwork)
|
||||
}
|
||||
|
||||
result.DNS = n.DNS
|
||||
|
||||
hnsEndpoint := &hcsshim.HNSEndpoint{
|
||||
Name: epName,
|
||||
VirtualNetwork: hnsNetwork.Id,
|
||||
DNSServerList: strings.Join(result.DNS.Nameservers, ","),
|
||||
DNSSuffix: strings.Join(result.DNS.Search, ","),
|
||||
GatewayAddress: gw.String(),
|
||||
IPAddress: result.IPs[0].Address.IP,
|
||||
Policies: n.MarshalPolicies(),
|
||||
}
|
||||
|
||||
return hnsEndpoint, nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Annotatef(err, "error while ProvisionEndpoint(%v,%v,%v)", epName, hnsNetwork.Id, args.ContainerID)
|
||||
}
|
||||
|
||||
result, err := hns.ConstructResult(hnsNetwork, hnsEndpoint)
|
||||
if err != nil {
|
||||
return errors.Annotatef(err, "error while constructResult")
|
||||
}
|
||||
|
||||
return types.PrintResult(result, cniVersion)
|
||||
}
|
||||
|
||||
func cmdDel(args *skel.CmdArgs) error {
|
||||
n, _, err := loadNetConf(args.StdinData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ipam.ExecDel(n.IPAM.Type, args.StdinData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name)
|
||||
|
||||
return hns.DeprovisionEndpoint(epName, args.Netns, args.ContainerID)
|
||||
}
|
||||
|
||||
func cmdGet(_ *skel.CmdArgs) error {
|
||||
// TODO: implement
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func main() {
|
||||
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
|
||||
}
|
27
plugins/main/windows/win-overlay/README.md
Normal file
27
plugins/main/windows/win-overlay/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# win-overlay plugin
|
||||
|
||||
## Overview
|
||||
|
||||
With win-overlay plugin, all containers (on the same host) are plugged into an Overlay network based on VXLAN encapsulation.
|
||||
|
||||
## Example configuration
|
||||
```
|
||||
{
|
||||
"name": "mynet",
|
||||
"type": "win-overlay",
|
||||
"ipMasq": true,
|
||||
"endpointMacPrefix": "0E-2A",
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.10.0.0/16"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Network configuration reference
|
||||
|
||||
* `name` (string, required): the name of the network.
|
||||
* `type` (string, required): "win-overlay".
|
||||
* `ipMasq` (bool, optional): the inverse of `$FLANNEL_IPMASQ`, setup NAT for the hnsNetwork subnet.
|
||||
* `endpointMacPrefix` (string, optional): set to the MAC prefix configured for Flannel
|
||||
* `ipam` (dictionary, required): IPAM configuration to be used for this network.
|
36
plugins/main/windows/win-overlay/sample.conf
Executable file
36
plugins/main/windows/win-overlay/sample.conf
Executable file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"cniVersion":"0.2.0",
|
||||
"name":"vxlan0",
|
||||
"type":"flannel",
|
||||
"delegate":{
|
||||
"type":"win-overlay",
|
||||
"dns":{
|
||||
"nameservers":[
|
||||
"11.0.0.10"
|
||||
],
|
||||
"search":[
|
||||
"svc.cluster.local"
|
||||
]
|
||||
},
|
||||
"policies":[
|
||||
{
|
||||
"name":"EndpointPolicy",
|
||||
"value":{
|
||||
"Type":"OutBoundNAT",
|
||||
"ExceptionList":[
|
||||
"192.168.0.0/16",
|
||||
"11.0.0.0/8"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"EndpointPolicy",
|
||||
"value":{
|
||||
"Type":"ROUTE",
|
||||
"DestinationPrefix":"11.0.0.0/8",
|
||||
"NeedEncap":true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
166
plugins/main/windows/win-overlay/win-overlay_windows.go
Normal file
166
plugins/main/windows/win-overlay/win-overlay_windows.go
Normal file
@ -0,0 +1,166 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/juju/errors"
|
||||
|
||||
"github.com/Microsoft/hcsshim"
|
||||
"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"
|
||||
"github.com/containernetworking/plugins/pkg/hns"
|
||||
"github.com/containernetworking/plugins/pkg/ipam"
|
||||
)
|
||||
|
||||
type NetConf struct {
|
||||
hns.NetConf
|
||||
|
||||
IPMasq bool `json:"ipMasq"`
|
||||
EndpointMacPrefix string `json:"endpointMacPrefix,omitempty"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
// this ensures that main runs only on main thread (thread group leader).
|
||||
// since namespace ops (unshare, setns) are done for a single thread, we
|
||||
// must ensure that the goroutine does not jump from OS thread to thread
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
func loadNetConf(bytes []byte) (*NetConf, string, error) {
|
||||
n := &NetConf{}
|
||||
if err := json.Unmarshal(bytes, n); err != nil {
|
||||
return nil, "", fmt.Errorf("failed to load netconf: %v", err)
|
||||
}
|
||||
return n, n.CNIVersion, nil
|
||||
}
|
||||
|
||||
func cmdAdd(args *skel.CmdArgs) error {
|
||||
n, cniVersion, err := loadNetConf(args.StdinData)
|
||||
if err != nil {
|
||||
return errors.Annotate(err, "error while loadNetConf")
|
||||
}
|
||||
|
||||
if len(n.EndpointMacPrefix) != 0 {
|
||||
if len(n.EndpointMacPrefix) != 5 || n.EndpointMacPrefix[2] != '-' {
|
||||
return fmt.Errorf("endpointMacPrefix [%v] is invalid, value must be of the format xx-xx", n.EndpointMacPrefix)
|
||||
}
|
||||
} else {
|
||||
n.EndpointMacPrefix = "0E-2A"
|
||||
}
|
||||
|
||||
networkName := n.Name
|
||||
hnsNetwork, err := hcsshim.GetHNSNetworkByName(networkName)
|
||||
if err != nil {
|
||||
return errors.Annotatef(err, "error while GETHNSNewtorkByName(%s)", networkName)
|
||||
}
|
||||
|
||||
if hnsNetwork == nil {
|
||||
return fmt.Errorf("network %v not found", networkName)
|
||||
}
|
||||
|
||||
if !strings.EqualFold(hnsNetwork.Type, "Overlay") {
|
||||
return fmt.Errorf("network %v is of an unexpected type: %v", networkName, hnsNetwork.Type)
|
||||
}
|
||||
|
||||
epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name)
|
||||
|
||||
hnsEndpoint, err := hns.ProvisionEndpoint(epName, hnsNetwork.Id, args.ContainerID, func() (*hcsshim.HNSEndpoint, error) {
|
||||
// run the IPAM plugin and get back the config to apply
|
||||
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "error while ipam.ExecAdd")
|
||||
}
|
||||
|
||||
// Convert whatever the IPAM result was into the current Result type
|
||||
result, err := current.NewResultFromResult(r)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "error while NewResultFromResult")
|
||||
}
|
||||
|
||||
if len(result.IPs) == 0 {
|
||||
return nil, errors.New("IPAM plugin return is missing IP config")
|
||||
}
|
||||
|
||||
ipAddr := result.IPs[0].Address.IP.To4()
|
||||
if ipAddr == nil {
|
||||
return nil, errors.New("win-overlay doesn't support IPv6 now")
|
||||
}
|
||||
|
||||
// conjure a MAC based on the IP for Overlay
|
||||
macAddr := fmt.Sprintf("%v-%02x-%02x-%02x-%02x", n.EndpointMacPrefix, ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3])
|
||||
// use the HNS network gateway
|
||||
gw := hnsNetwork.Subnets[0].GatewayAddress
|
||||
n.ApplyDefaultPAPolicy(hnsNetwork.ManagementIP)
|
||||
if n.IPMasq {
|
||||
n.ApplyOutboundNatPolicy(hnsNetwork.Subnets[0].AddressPrefix)
|
||||
}
|
||||
|
||||
result.DNS = n.DNS
|
||||
|
||||
hnsEndpoint := &hcsshim.HNSEndpoint{
|
||||
Name: epName,
|
||||
VirtualNetwork: hnsNetwork.Id,
|
||||
DNSServerList: strings.Join(result.DNS.Nameservers, ","),
|
||||
DNSSuffix: strings.Join(result.DNS.Search, ","),
|
||||
GatewayAddress: gw,
|
||||
IPAddress: ipAddr,
|
||||
MacAddress: macAddr,
|
||||
Policies: n.MarshalPolicies(),
|
||||
}
|
||||
|
||||
return hnsEndpoint, nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Annotatef(err, "error while ProvisionEndpoint(%v,%v,%v)", epName, hnsNetwork.Id, args.ContainerID)
|
||||
}
|
||||
|
||||
result, err := hns.ConstructResult(hnsNetwork, hnsEndpoint)
|
||||
if err != nil {
|
||||
return errors.Annotatef(err, "error while constructResult")
|
||||
}
|
||||
|
||||
return types.PrintResult(result, cniVersion)
|
||||
}
|
||||
|
||||
func cmdDel(args *skel.CmdArgs) error {
|
||||
n, _, err := loadNetConf(args.StdinData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ipam.ExecDel(n.IPAM.Type, args.StdinData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name)
|
||||
|
||||
return hns.DeprovisionEndpoint(epName, args.Netns, args.ContainerID)
|
||||
}
|
||||
|
||||
func cmdGet(_ *skel.CmdArgs) error {
|
||||
// TODO: implement
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func main() {
|
||||
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
|
||||
}
|
@ -86,3 +86,50 @@ flannel plugin will set the following fields in the delegated plugin configurati
|
||||
* `mtu`: `$FLANNEL_MTU`
|
||||
|
||||
Additionally, for the bridge plugin, `isGateway` will be set to `true`, if not present.
|
||||
|
||||
## Windows Support (Experimental)
|
||||
This plugin supports delegating to the windows CNI plugins (overlay.exe, l2bridge.exe) to work in conjunction with [Flannel on Windows](https://github.com/coreos/flannel/issues/833).
|
||||
Flannel sets up an [HNS Network](https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/container-networking) in L2Bridge mode for host-gw and in Overlay mode for vxlan.
|
||||
|
||||
The following fields must be set in the delegated plugin configuration:
|
||||
* `name` (string, required): the name of the network (must match the name in Flannel config / name of the HNS network)
|
||||
* `type` (string, optional): set to `win-l2bridge` by default. Can be set to `win-overlay` or other custom windows CNI
|
||||
* `ipMasq`: the inverse of `$FLANNEL_IPMASQ`
|
||||
* `endpointMacPrefix` (string, optional): required for `win-overlay` mode, set to the MAC prefix configured for Flannel
|
||||
* `clusterNetworkPrefix` (string, optional): required for `win-l2bridge` mode, setup NAT if `ipMasq` is set to true
|
||||
|
||||
For `win-l2bridge`, the Flannel CNI plugin will set:
|
||||
* `ipam`: "host-local" type will be used with "subnet" set to `$FLANNEL_SUBNET` and gateway as the .2 address in `$FLANNEL_NETWORK`
|
||||
|
||||
For `win-overlay`, the Flannel CNI plugin will set:
|
||||
* `ipam`: "host-local" type will be used with "subnet" set to `$FLANNEL_SUBNET` and gateway as the .1 address in `$FLANNEL_NETWORK`
|
||||
|
||||
If IPMASQ is true, the Flannel CNI plugin will setup an OutBoundNAT policy and add FLANNEL_SUBNET to any existing exclusions.
|
||||
|
||||
All other delegate config e.g. other HNS endpoint policies in AdditionalArgs will be passed to WINCNI as-is.
|
||||
|
||||
Example VXLAN Flannel CNI config
|
||||
```
|
||||
{
|
||||
"name": "mynet",
|
||||
"type": "flannel",
|
||||
"delegate": {
|
||||
"type": "win-overlay",
|
||||
"endpointMacPrefix": "0E-2A"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For this example, Flannel CNI would generate the following config to delegate to the windows CNI when FLANNEL_NETWORK=10.244.0.0/16, FLANNEL_SUBNET=10.244.1.0/24 and IPMASQ=true
|
||||
```
|
||||
{
|
||||
"name": "mynet",
|
||||
"type": "win-overlay",
|
||||
"endpointMacPrefix": "0E-2A",
|
||||
"ipMasq": true,
|
||||
"ipam": {
|
||||
"subnet": "10.244.1.0/24",
|
||||
"type": "host-local"
|
||||
}
|
||||
}
|
||||
```
|
@ -42,6 +42,7 @@ const (
|
||||
|
||||
type NetConf struct {
|
||||
types.NetConf
|
||||
|
||||
SubnetFile string `json:"subnetFile"`
|
||||
DataDir string `json:"dataDir"`
|
||||
Delegate map[string]interface{} `json:"delegate"`
|
||||
@ -202,43 +203,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
}
|
||||
|
||||
n.Delegate["name"] = n.Name
|
||||
|
||||
if !hasKey(n.Delegate, "type") {
|
||||
n.Delegate["type"] = "bridge"
|
||||
}
|
||||
|
||||
if !hasKey(n.Delegate, "ipMasq") {
|
||||
// if flannel is not doing ipmasq, we should
|
||||
ipmasq := !*fenv.ipmasq
|
||||
n.Delegate["ipMasq"] = ipmasq
|
||||
}
|
||||
|
||||
if !hasKey(n.Delegate, "mtu") {
|
||||
mtu := fenv.mtu
|
||||
n.Delegate["mtu"] = mtu
|
||||
}
|
||||
|
||||
if n.Delegate["type"].(string) == "bridge" {
|
||||
if !hasKey(n.Delegate, "isGateway") {
|
||||
n.Delegate["isGateway"] = true
|
||||
}
|
||||
}
|
||||
if n.CNIVersion != "" {
|
||||
n.Delegate["cniVersion"] = n.CNIVersion
|
||||
}
|
||||
|
||||
n.Delegate["ipam"] = map[string]interface{}{
|
||||
"type": "host-local",
|
||||
"subnet": fenv.sn.String(),
|
||||
"routes": []types.Route{
|
||||
types.Route{
|
||||
Dst: *fenv.nw,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return delegateAdd(args.ContainerID, n.DataDir, n.Delegate)
|
||||
return doCmdAdd(args, n, fenv)
|
||||
}
|
||||
|
||||
func cmdDel(args *skel.CmdArgs) error {
|
||||
@ -247,25 +212,10 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
return err
|
||||
}
|
||||
|
||||
netconfBytes, err := consumeScratchNetConf(args.ContainerID, nc.DataDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// Per spec should ignore error if resources are missing / already removed
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
n := &types.NetConf{}
|
||||
if err = json.Unmarshal(netconfBytes, n); err != nil {
|
||||
return fmt.Errorf("failed to parse netconf: %v", err)
|
||||
}
|
||||
|
||||
return invoke.DelegateDel(n.Type, netconfBytes, nil)
|
||||
return doCmdDel(args, nc)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// TODO: implement plugin version
|
||||
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
|
||||
}
|
||||
|
||||
|
86
plugins/meta/flannel/flannel_linux.go
Normal file
86
plugins/meta/flannel/flannel_linux.go
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2018 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 "meta-plugin". It reads in its own netconf, combines it with
|
||||
// the data from flannel generated subnet file and then invokes a plugin
|
||||
// like bridge or ipvlan to do the real work.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/containernetworking/cni/pkg/invoke"
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"os"
|
||||
)
|
||||
|
||||
func doCmdAdd(args *skel.CmdArgs, n *NetConf, fenv *subnetEnv) error {
|
||||
n.Delegate["name"] = n.Name
|
||||
|
||||
if !hasKey(n.Delegate, "type") {
|
||||
n.Delegate["type"] = "bridge"
|
||||
}
|
||||
|
||||
if !hasKey(n.Delegate, "ipMasq") {
|
||||
// if flannel is not doing ipmasq, we should
|
||||
ipmasq := !*fenv.ipmasq
|
||||
n.Delegate["ipMasq"] = ipmasq
|
||||
}
|
||||
|
||||
if !hasKey(n.Delegate, "mtu") {
|
||||
mtu := fenv.mtu
|
||||
n.Delegate["mtu"] = mtu
|
||||
}
|
||||
|
||||
if n.Delegate["type"].(string) == "bridge" {
|
||||
if !hasKey(n.Delegate, "isGateway") {
|
||||
n.Delegate["isGateway"] = true
|
||||
}
|
||||
}
|
||||
if n.CNIVersion != "" {
|
||||
n.Delegate["cniVersion"] = n.CNIVersion
|
||||
}
|
||||
|
||||
n.Delegate["ipam"] = map[string]interface{}{
|
||||
"type": "host-local",
|
||||
"subnet": fenv.sn.String(),
|
||||
"routes": []types.Route{
|
||||
{
|
||||
Dst: *fenv.nw,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return delegateAdd(args.ContainerID, n.DataDir, n.Delegate)
|
||||
}
|
||||
|
||||
func doCmdDel(args *skel.CmdArgs, n *NetConf) error {
|
||||
netconfBytes, err := consumeScratchNetConf(args.ContainerID, n.DataDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// Per spec should ignore error if resources are missing / already removed
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
nc := &types.NetConf{}
|
||||
if err = json.Unmarshal(netconfBytes, nc); err != nil {
|
||||
return fmt.Errorf("failed to parse netconf: %v", err)
|
||||
}
|
||||
|
||||
return invoke.DelegateDel(nc.Type, netconfBytes, nil)
|
||||
}
|
73
plugins/meta/flannel/flannel_windows.go
Normal file
73
plugins/meta/flannel/flannel_windows.go
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright 2018 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 "meta-plugin". It reads in its own netconf, combines it with
|
||||
// the data from flannel generated subnet file and then invokes a plugin
|
||||
// like bridge or ipvlan to do the real work.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/containernetworking/cni/pkg/invoke"
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/containernetworking/cni/pkg/types/020"
|
||||
"github.com/containernetworking/plugins/pkg/hns"
|
||||
"os"
|
||||
)
|
||||
|
||||
func doCmdAdd(args *skel.CmdArgs, n *NetConf, fenv *subnetEnv) error {
|
||||
n.Delegate["name"] = n.Name
|
||||
|
||||
if !hasKey(n.Delegate, "type") {
|
||||
n.Delegate["type"] = "win-bridge"
|
||||
}
|
||||
|
||||
// if flannel needs ipmasq - get the plugin to configure it
|
||||
// (this is the opposite of how linux works - on linux the flannel daemon configure ipmasq)
|
||||
n.Delegate["ipMasq"] = *fenv.ipmasq
|
||||
n.Delegate["ipMasqNetwork"] = fenv.nw.String()
|
||||
|
||||
n.Delegate["cniVersion"] = types020.ImplementedSpecVersion
|
||||
if len(n.CNIVersion) != 0 {
|
||||
n.Delegate["cniVersion"] = n.CNIVersion
|
||||
}
|
||||
|
||||
n.Delegate["ipam"] = map[string]interface{}{
|
||||
"type": "host-local",
|
||||
"subnet": fenv.sn.String(),
|
||||
}
|
||||
|
||||
return delegateAdd(hns.GetSandboxContainerID(args.ContainerID, args.Netns), n.DataDir, n.Delegate)
|
||||
}
|
||||
|
||||
func doCmdDel(args *skel.CmdArgs, n *NetConf) error {
|
||||
netconfBytes, err := consumeScratchNetConf(hns.GetSandboxContainerID(args.ContainerID, args.Netns), n.DataDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// Per spec should ignore error if resources are missing / already removed
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
nc := &types.NetConf{}
|
||||
if err = json.Unmarshal(netconfBytes, nc); err != nil {
|
||||
return fmt.Errorf("failed to parse netconf: %v", err)
|
||||
}
|
||||
|
||||
return invoke.DelegateDel(nc.Type, netconfBytes, nil)
|
||||
}
|
4
plugins/windows_only.txt
Normal file
4
plugins/windows_only.txt
Normal file
@ -0,0 +1,4 @@
|
||||
plugins/ipam/host-local
|
||||
plugins/main/windows/win-bridge
|
||||
plugins/main/windows/win-overlay
|
||||
plugins/meta/flannel
|
Reference in New Issue
Block a user