Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows CNI support #193

Merged
merged 2 commits into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 3 additions & 2 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ environment:
install:
- echo %PATH%
- echo %GOPATH%
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- go version
- go env
- ps: $webClient = New-Object System.Net.WebClient; $InstallPath="c:" ; $webClient.DownloadFile("https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip", "$InstallPath\gcc.zip"); Expand-Archive $InstallPath\gcc.zip -DestinationPath $InstallPath\gcc -Force; $webClient.DownloadFile("https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/runtime.zip", "$InstallPath\runtime.zip"); Expand-Archive $InstallPath\runtime.zip -DestinationPath $InstallPath\gcc -Force; $webClient.DownloadFile("https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/binutils.zip","$InstallPath\binutils.zip"); Expand-Archive $InstallPath\binutils.zip -DestinationPath $InstallPath\gcc -Force;
- set PATH=%GOPATH%\bin;c:\go\bin;c:\gcc\bin;%PATH%

build: off

test_script:
- ps: |
go list ./... | Select-String -Pattern (Get-Content "./plugins/linux_only.txt") -NotMatch > "to_test.txt"
go list ./... | Select-String -Pattern (Get-Content "./plugins/windows_only.txt") > "to_test.txt"
echo "Will test:"
Get-Content "to_test.txt"
foreach ($pkg in Get-Content "to_test.txt") {
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ _testmain.go
bin/
gopath/
.vagrant

.idea
/release-*
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ matrix:
fast_finish: true

install:
- sudo apt-get install gcc-multilib gcc-mingw-w64 -y
- go get github.com/onsi/ginkgo/ginkgo
- go get github.com/containernetworking/cni/cnitool

Expand Down
96 changes: 95 additions & 1 deletion Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ Read [CONTRIBUTING](CONTRIBUTING.md) for build and test instructions.
* `macvlan`: Creates a new MAC address, forwards all traffic to that to the container.
* `ptp`: Creates a veth pair.
* `vlan`: Allocates a vlan device.

#### Windows: windows specific
* `win-bridge`: Creates a bridge, adds the host and the container to it.
* `win-overlay`: Creates an overlay interface to the container.
### IPAM: IP address allocation
* `dhcp`: Runs a daemon on the host to make DHCP requests on behalf of the container
* `host-local`: maintains a local database of allocated IPs
Expand Down
7 changes: 2 additions & 5 deletions Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@ Vagrant.configure(2) do |config|

config.vm.provision "shell", inline: <<-SHELL
set -e -x -u

apt-get update -y || (sleep 40 && apt-get update -y)
apt-get install -y git

apt-get install -y git gcc-multilib gcc-mingw-w64
wget -qO- https://storage.googleapis.com/golang/go1.10.linux-amd64.tar.gz | tar -C /usr/local -xz

echo 'export GOPATH=/go' >> /root/.bashrc
echo 'export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin' >> /root/.bashrc
cd /go/src/github.com/containernetworking/plugins
SHELL
end
end
14 changes: 11 additions & 3 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@ export GO="${GO:-go}"

mkdir -p "${PWD}/bin"

echo "Building plugins"
echo "Building plugins ${GOOS}"
PLUGINS="plugins/meta/* plugins/main/* plugins/ipam/* plugins/sample"
for d in $PLUGINS; do
if [ -d "$d" ]; then
plugin="$(basename "$d")"
echo " $plugin"
$GO build -o "${PWD}/bin/$plugin" "$@" "$REPO_PATH"/$d
if [ $plugin == "windows" ]
then
if [ "$GOARCH" == "amd64" ]
then
GOOS=windows . $d/build.sh
fi
else
echo " $plugin"
$GO build -o "${PWD}/bin/$plugin" "$@" "$REPO_PATH"/$d
fi
fi
done
152 changes: 152 additions & 0 deletions pkg/hns/endpoint_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// 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 hns

import (
"fmt"
"net"
"strings"

"github.com/Microsoft/hcsshim"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/juju/errors"
)

const (
pauseContainerNetNS = "none"
)

// GetSandboxContainerID returns the sandbox ID of this pod
func GetSandboxContainerID(containerID string, netNs string) string {
if len(netNs) != 0 && netNs != pauseContainerNetNS {
splits := strings.SplitN(netNs, ":", 2)
if len(splits) == 2 {
containerID = splits[1]
}
}

return containerID
}

// ConstructEndpointName constructs enpointId which is used to identify an endpoint from HNS
// There is a special consideration for netNs name here, which is required for Windows Server 1709
// containerID is the Id of the container on which the endpoint is worked on
func ConstructEndpointName(containerID string, netNs string, networkName string) string {
return GetSandboxContainerID(containerID, netNs) + "_" + networkName
}

// DeprovisionEndpoint removes an endpoint from the container by sending a Detach request to HNS
// For shared endpoint, ContainerDetach is used
// for removing the endpoint completely, HotDetachEndpoint is used
func DeprovisionEndpoint(epName string, netns string, containerID string) error {
if len(netns) == 0 {
return nil
}

hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epName)
if err != nil {
return errors.Annotatef(err, "failed to find HNSEndpoint %s", epName)
}

if netns != pauseContainerNetNS {
// Shared endpoint removal. Do not remove the endpoint.
hnsEndpoint.ContainerDetach(containerID)
return nil
}

// Do not consider this as failure, else this would leak endpoints
hcsshim.HotDetachEndpoint(containerID, hnsEndpoint.Id)

// Do not return error
hnsEndpoint.Delete()

return nil
}

type EndpointMakerFunc func() (*hcsshim.HNSEndpoint, error)

// ProvisionEndpoint provisions an endpoint to a container specified by containerID.
// If an endpoint already exists, the endpoint is reused.
// This call is idempotent
func ProvisionEndpoint(epName string, expectedNetworkId string, containerID string, makeEndpoint EndpointMakerFunc) (*hcsshim.HNSEndpoint, error) {
// check if endpoint already exists
createEndpoint := true
hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epName)
if hnsEndpoint != nil && hnsEndpoint.VirtualNetwork == expectedNetworkId {
createEndpoint = false
}

if createEndpoint {
if hnsEndpoint != nil {
if _, err = hnsEndpoint.Delete(); err != nil {
return nil, errors.Annotate(err, "failed to delete the stale HNSEndpoint")
}
}

if hnsEndpoint, err = makeEndpoint(); err != nil {
return nil, errors.Annotate(err, "failed to make a new HNSEndpoint")
}

if hnsEndpoint, err = hnsEndpoint.Create(); err != nil {
return nil, errors.Annotate(err, "failed to create the new HNSEndpoint")
}

}

// hot attach
if err := hcsshim.HotAttachEndpoint(containerID, hnsEndpoint.Id); err != nil {
if hcsshim.ErrComputeSystemDoesNotExist == err {
return hnsEndpoint, nil
}

return nil, err
}

return hnsEndpoint, nil
}

// ConstructResult constructs the CNI result for the endpoint
func ConstructResult(hnsNetwork *hcsshim.HNSNetwork, hnsEndpoint *hcsshim.HNSEndpoint) (*current.Result, error) {
resultInterface := &current.Interface{
Name: hnsEndpoint.Name,
Mac: hnsEndpoint.MacAddress,
}
_, ipSubnet, err := net.ParseCIDR(hnsNetwork.Subnets[0].AddressPrefix)
if err != nil {
return nil, errors.Annotatef(err, "failed to parse CIDR from %s", hnsNetwork.Subnets[0].AddressPrefix)
}

var ipVersion string
if ipv4 := hnsEndpoint.IPAddress.To4(); ipv4 != nil {
ipVersion = "4"
} else if ipv6 := hnsEndpoint.IPAddress.To16(); ipv6 != nil {
ipVersion = "6"
} else {
return nil, fmt.Errorf("IPAddress of HNSEndpoint %s isn't a valid ipv4 or ipv6 Address", hnsEndpoint.Name)
}

resultIPConfig := &current.IPConfig{
Version: ipVersion,
Address: net.IPNet{
IP: hnsEndpoint.IPAddress,
Mask: ipSubnet.Mask},
Gateway: net.ParseIP(hnsEndpoint.GatewayAddress),
}
result := &current.Result{}
result.Interfaces = []*current.Interface{resultInterface}
result.IPs = []*current.IPConfig{resultIPConfig}

return result, nil
}
Loading