diff --git a/.gitignore b/.gitignore index 331501803f..c9274d2f13 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ ipam-*.xml # Environment .vscode/* + +# Coverage +*.out \ No newline at end of file diff --git a/.pipelines/Dockerfile b/.pipelines/Dockerfile new file mode 100644 index 0000000000..f515ab9a45 --- /dev/null +++ b/.pipelines/Dockerfile @@ -0,0 +1,16 @@ +FROM ubuntu:16.04 +RUN apt-get update && apt-get install -y software-properties-common sudo wget apt-transport-https curl +RUN wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb +RUN sudo dpkg -i packages-microsoft-prod.deb +RUN add-apt-repository ppa:longsleep/golang-backports && apt-get update +RUN apt-get install -y git golang-go=2:1.13~1longsleep1+xenial iptables ipset iproute2 ebtables python-pip gcc zip dotnet-sdk-2.2 +RUN sudo pip install coverage +RUN if [ -f Gopkg.toml ]; then curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh ; fi +RUN go get github.com/docker/libnetwork/driverapi +RUN go get github.com/gorilla/mux +RUN go get github.com/jstemmer/go-junit-report +RUN go get github.com/axw/gocov/gocov +RUN go get github.com/AlekSi/gocov-xml +RUN go get -u gopkg.in/matm/v1/gocov-html +ENV PATH="/root/go/bin:${PATH}" + diff --git a/.pipelines/pipeline.yml b/.pipelines/pipeline.yml new file mode 100644 index 0000000000..c4d07f51b3 --- /dev/null +++ b/.pipelines/pipeline.yml @@ -0,0 +1,122 @@ +pr: + - master + +trigger: + branches: + include: + - master + +jobs: + - job: UnitTest + pool: + name: Networking-ContainerNetworking + demands: agent.os -equals Linux + + container: + image: containernetworking/pipeline-ci:1.0.3 + options: "--privileged" + + # Go setup for the vmImage: + # https://github.com/Microsoft/azure-pipelines-image-generation/blob/master/images/linux/scripts/installers/go.sh + variables: + GOBIN: "$(GOPATH)/bin" # Go binaries path + GOPATH: "$(System.DefaultWorkingDirectory)/gopath" # Go workspace path + modulePath: "$(GOPATH)/src/github.com/Azure/azure-container-networking" # $(build.repository.name)' # Path to the module's code + + steps: + - bash: | + echo $UID + sudo apt-get install -y ebtables ipset python3-dev gcc zip iptables ipset + sudo pip install coverage + displayName: "Install OS dependencies" + + - bash: | + go version + go env + mkdir -p '$(GOBIN)' + mkdir -p '$(GOPATH)/pkg' + mkdir -p '$(modulePath)' + shopt -s extglob + shopt -s dotglob + mv !(gopath) '$(modulePath)' + echo '##vso[task.prependpath]$(GOBIN)' + echo '##vso[task.prependpath]$(GOROOT)/bin' + displayName: "Set up the Go workspace" + + - bash: | + go get -v -t -d ./... + if [ -f Gopkg.toml ]; then + curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh + fi + go get github.com/docker/libnetwork/driverapi + go get github.com/gorilla/mux + go get github.com/jstemmer/go-junit-report + go get github.com/axw/gocov/gocov + go get github.com/AlekSi/gocov-xml + go get -u gopkg.in/matm/v1/gocov-html + workingDirectory: "$(modulePath)" + displayName: "Install Go dependencies" + + - bash: | + sudo rm /run/docker/plugins/test.sock || true + sudo ip link del dev dummy || true + workingDirectory: "$(modulePath)" + displayName: "Workspace setup" + condition: always() + + - bash: | + export GOOS=linux + make all-binaries + export GOOS=windows + make all-binaries + cd output + sudo find . -mindepth 2 -type f -regextype posix-extended ! -iregex '.*\.(zip|tgz)$' -delete + sudo find . -mindepth 2 -type f -print -exec mv {} . \; + sudo rm -R -- */ + workingDirectory: "$(modulePath)" + displayName: "Build" + + - bash: | + # run test, echo exit status code to fd 3, pipe output from test to tee, which splits output to stdout and go-junit-report (which converts test output to report.xml), stdout from tee is redirected to fd 4. Take output written to fd 3 (which is the exit code of test), redirect to stdout, pipe to read from stdout then exit with that status code. Read all output from fd 4 (output from tee) and write to top stdout + { { { { + sudo -E env "PATH=$PATH" make test-all; + echo $? >&3; + } | tee >(go-junit-report > report.xml) >&4; + } 3>&1; + } | { read xs; exit $xs; } + } 4>&1 + workingDirectory: "$(modulePath)" + failOnStderr: true + displayName: "Run Tests" + + - bash: | + bash <(curl -s https://codecov.io/bash) + gocov convert coverage.out > coverage.json + gocov-xml < coverage.json > coverage.xml + workingDirectory: "$(modulePath)" + displayName: "Generate Coverage Reports" + condition: always() + + - task: PublishTestResults@2 + inputs: + testRunner: JUnit + testResultsFiles: $(System.DefaultWorkingDirectory)/**/report.xml + condition: always() + + - task: PublishCodeCoverageResults@1 + inputs: + codeCoverageTool: Cobertura + summaryFileLocation: $(System.DefaultWorkingDirectory)/**/coverage.xml + condition: always() + + - task: CopyFiles@2 + inputs: + sourceFolder: "$(modulePath)/output" + targetFolder: $(Build.ArtifactStagingDirectory) + condition: succeeded() + + - task: PublishBuildArtifacts@1 + inputs: + artifactName: "output" + pathtoPublish: "$(Build.ArtifactStagingDirectory)" + condition: succeeded() diff --git a/Makefile b/Makefile index af3b7b4a84..d04844f00d 100644 --- a/Makefile +++ b/Makefile @@ -301,4 +301,20 @@ ifeq ($(GOOS),linux) cp telemetry/azure-vnet-telemetry.config $(NPM_BUILD_DIR)/azure-vnet-telemetry.config cd $(NPM_BUILD_DIR) && $(ARCHIVE_CMD) $(NPM_ARCHIVE_NAME) azure-npm$(EXE_EXT) azure-vnet-telemetry$(EXE_EXT) azure-vnet-telemetry.config chown $(BUILD_USER):$(BUILD_USER) $(NPM_BUILD_DIR)/$(NPM_ARCHIVE_NAME) -endif \ No newline at end of file +endif + +# run all tests +.PHONY: test-all +test-all: + go test -v -covermode count -coverprofile=coverage.out \ + ./ipam/ \ + ./log/ \ + ./netlink/ \ + ./store/ \ + ./telemetry/ \ + ./cnm/network/ \ + ./cni/ipam/ \ + ./cns/ipamclient/ \ + ./npm/iptm/ \ + ./npm/ipsm/ \ + ./npm \ No newline at end of file diff --git a/README.md b/README.md index 9634a1d896..6c51c86e91 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Microsoft Azure Container Networking -[![CircleCI](https://circleci.com/gh/Azure/azure-container-networking/tree/master.svg?style=svg)](https://circleci.com/gh/Azure/azure-container-networking/tree/master) [![Go Report Card](https://goreportcard.com/badge/github.com/Azure/azure-container-networking)](https://goreportcard.com/report/github.com/Azure/azure-container-networking) ![GitHub release](https://img.shields.io/github/release/Azure/azure-container-networking.svg) +[![Build Status](https://msazure.visualstudio.com/One/_apis/build/status/Custom/Networking/ContainerNetworking/Azure.azure-container-networking?branchName=master)](https://msazure.visualstudio.com/One/_build/latest?definitionId=95007&branchName=master) [![Go Report Card](https://goreportcard.com/badge/github.com/Azure/azure-container-networking)](https://goreportcard.com/report/github.com/Azure/azure-container-networking) ![GitHub release](https://img.shields.io/github/release/Azure/azure-container-networking.svg) [![codecov](https://codecov.io/gh/Azure/azure-container-networking/branch/master/graph/badge.svg)](https://codecov.io/gh/Azure/azure-container-networking) ## Overview diff --git a/network/network_linux.go b/network/network_linux.go index b2966790de..195fcccc86 100644 --- a/network/network_linux.go +++ b/network/network_linux.go @@ -269,14 +269,19 @@ func (nm *networkManager) applyIPConfig(extIf *externalInterface, targetIf *net. } func applyDnsConfig(extIf *externalInterface, ifName string) error { - cmd := fmt.Sprintf("systemd-resolve --interface=%s --set-dns=%s", ifName, extIf.DNSInfo.Servers[0]) - _, err := platform.ExecuteCommand(cmd) - if err != nil { - return err + var err error + + if extIf != nil && len(extIf.DNSInfo.Servers) > 0 { + cmd := fmt.Sprintf("systemd-resolve --interface=%s --set-dns=%s", ifName, extIf.DNSInfo.Servers[0]) + _, err = platform.ExecuteCommand(cmd) + if err != nil { + return err + } + + cmd = fmt.Sprintf("systemd-resolve --interface=%s --set-domain=%s", ifName, extIf.DNSInfo.Suffix) + _, err = platform.ExecuteCommand(cmd) } - cmd = fmt.Sprintf("systemd-resolve --interface=%s --set-domain=%s", ifName, extIf.DNSInfo.Suffix) - _, err = platform.ExecuteCommand(cmd) return err } diff --git a/npm/ipsm/ipsm.go b/npm/ipsm/ipsm.go index 79c08fc853..0aab88fc46 100644 --- a/npm/ipsm/ipsm.go +++ b/npm/ipsm/ipsm.go @@ -350,8 +350,8 @@ func (ipsMgr *IpsetManager) Run(entry *ipsEntry) (int, error) { _, err := exec.Command(cmdName, cmdArgs...).Output() if msg, failed := err.(*exec.ExitError); failed { errCode := msg.Sys().(syscall.WaitStatus).ExitStatus() - if errCode > 1 { - log.Errorf("Error: There was an error running command: %s %s Arguments:%v", err, cmdName, cmdArgs) + if errCode > 0 { + log.Errorf("Error: There was an error running command: [%s %v] Stderr: [%v, %s]", cmdName, strings.Join(cmdArgs, " "), err, strings.TrimSuffix(string(msg.Stderr), "\n")) } return errCode, err diff --git a/npm/ipsm/ipsm_test.go b/npm/ipsm/ipsm_test.go index 818941d4dc..5735ae1a1f 100644 --- a/npm/ipsm/ipsm_test.go +++ b/npm/ipsm/ipsm_test.go @@ -4,6 +4,7 @@ package ipsm import ( "testing" + "os" "github.com/Azure/azure-container-networking/npm/util" ) @@ -76,6 +77,10 @@ func TestAddToList(t *testing.T) { } }() + if err := ipsMgr.CreateSet("test-set"); err != nil { + t.Errorf("TestAddToList failed @ ipsMgr.CreateSet") + } + if err := ipsMgr.AddToList("test-list", "test-set"); err != nil { t.Errorf("TestAddToList failed @ ipsMgr.AddToList") } @@ -93,6 +98,10 @@ func TestDeleteFromList(t *testing.T) { } }() + if err := ipsMgr.CreateSet("test-set"); err != nil { + t.Errorf("TestDeleteFromList failed @ ipsMgr.CreateSet") + } + if err := ipsMgr.AddToList("test-list", "test-set"); err != nil { t.Errorf("TestDeleteFromList failed @ ipsMgr.AddToList") } @@ -100,6 +109,10 @@ func TestDeleteFromList(t *testing.T) { if err := ipsMgr.DeleteFromList("test-list", "test-set"); err != nil { t.Errorf("TestDeleteFromList failed @ ipsMgr.DeleteFromList") } + + if err := ipsMgr.DeleteSet("test-set"); err != nil { + t.Errorf("TestDeleteSet failed @ ipsMgr.DeleteSet") + } } func TestCreateSet(t *testing.T) { @@ -246,7 +259,9 @@ func TestMain(m *testing.M) { ipsMgr := NewIpsetManager() ipsMgr.Save(util.IpsetConfigFile) - m.Run() + exitCode := m.Run() ipsMgr.Restore(util.IpsetConfigFile) + + os.Exit(exitCode) } diff --git a/npm/iptm/iptm.go b/npm/iptm/iptm.go index 5d2e0d74a2..ea4705ee5c 100644 --- a/npm/iptm/iptm.go +++ b/npm/iptm/iptm.go @@ -9,6 +9,7 @@ package iptm import ( "os" "os/exec" + "strings" "syscall" "time" @@ -365,8 +366,8 @@ func (iptMgr *IptablesManager) Run(entry *IptEntry) (int, error) { if msg, failed := err.(*exec.ExitError); failed { errCode := msg.Sys().(syscall.WaitStatus).ExitStatus() - if errCode > 1 { - log.Errorf("Error: There was an error running command: %s %s Arguments:%v", err, cmdName, cmdArgs) + if errCode > 0 { + log.Errorf("Error: There was an error running command: [%s %v] Stderr: [%v, %s]", cmdName, strings.Join(cmdArgs, " "), err, strings.TrimSuffix(string(msg.Stderr), "\n")) } return errCode, err diff --git a/npm/iptm/iptm_test.go b/npm/iptm/iptm_test.go index ba483a9bf9..04a454d6a5 100644 --- a/npm/iptm/iptm_test.go +++ b/npm/iptm/iptm_test.go @@ -2,6 +2,7 @@ package iptm import ( "testing" + "os" "github.com/Azure/azure-container-networking/npm/util" ) @@ -204,7 +205,9 @@ func TestMain(m *testing.M) { iptMgr := NewIptablesManager() iptMgr.Save(util.IptablesConfigFile) - m.Run() + exitCode := m.Run() iptMgr.Restore(util.IptablesConfigFile) + + os.Exit(exitCode) } diff --git a/npm/namespace_test.go b/npm/namespace_test.go index a446ad70d8..74814fc9e3 100644 --- a/npm/namespace_test.go +++ b/npm/namespace_test.go @@ -4,6 +4,7 @@ package npm import ( "testing" + "os" "github.com/Azure/azure-container-networking/npm/iptm" "github.com/Azure/azure-container-networking/telemetry" @@ -190,8 +191,10 @@ func TestMain(m *testing.M) { ipsMgr := ipsm.NewIpsetManager() ipsMgr.Save(util.IpsetConfigFile) - m.Run() + exitCode := m.Run() iptMgr.Restore(util.IptablesConfigFile) ipsMgr.Restore(util.IpsetConfigFile) + + os.Exit(exitCode) } diff --git a/npm/nwpolicy_test.go b/npm/nwpolicy_test.go index e6f48ce72d..352cd5b5b6 100644 --- a/npm/nwpolicy_test.go +++ b/npm/nwpolicy_test.go @@ -42,6 +42,11 @@ func TestAddNetworkPolicy(t *testing.T) { t.Errorf("TestAddNetworkPolicy failed @ ipsMgr.Save") } + // Create ns-kube-system set + if err := ipsMgr.CreateSet("ns-" + util.KubeSystemFlag); err != nil { + t.Errorf("TestAddNetworkPolicy failed @ ipsMgr.CreateSet, adding kube-system set%+v", err) + } + defer func() { if err := iptMgr.Restore(util.IptablesTestConfigFile); err != nil { t.Errorf("TestAddNetworkPolicy failed @ iptMgr.Restore") @@ -140,24 +145,29 @@ func TestUpdateNetworkPolicy(t *testing.T) { iptMgr := iptm.NewIptablesManager() if err := iptMgr.Save(util.IptablesTestConfigFile); err != nil { - t.Errorf("UpdateAddNetworkPolicy failed @ iptMgr.Save") + t.Errorf("TestUpdateNetworkPolicy failed @ iptMgr.Save") } ipsMgr := ipsm.NewIpsetManager() if err := ipsMgr.Save(util.IpsetTestConfigFile); err != nil { - t.Errorf("UpdateAddNetworkPolicy failed @ ipsMgr.Save") + t.Errorf("TestUpdateNetworkPolicy failed @ ipsMgr.Save") } defer func() { if err := iptMgr.Restore(util.IptablesTestConfigFile); err != nil { - t.Errorf("UpdateAddNetworkPolicy failed @ iptMgr.Restore") + t.Errorf("TestUpdateNetworkPolicy failed @ iptMgr.Restore") } if err := ipsMgr.Restore(util.IpsetTestConfigFile); err != nil { - t.Errorf("UpdateAddNetworkPolicy failed @ ipsMgr.Restore") + t.Errorf("TestUpdateNetworkPolicy failed @ ipsMgr.Restore") } }() + // Create ns-kube-system set + if err := ipsMgr.CreateSet("ns-" + util.KubeSystemFlag); err != nil { + t.Errorf("TestUpdateNetworkPolicy failed @ ipsMgr.CreateSet, adding kube-system set%+v", err) + } + nsObj := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: "test-nwpolicy", @@ -168,7 +178,7 @@ func TestUpdateNetworkPolicy(t *testing.T) { } if err := npMgr.AddNamespace(nsObj); err != nil { - t.Errorf("TestAddNetworkPolicy @ npMgr.AddNamespace") + t.Errorf("TestUpdateNetworkPolicy @ npMgr.AddNamespace") } tcp, udp := corev1.ProtocolTCP, corev1.ProtocolUDP @@ -265,6 +275,11 @@ func TestDeleteNetworkPolicy(t *testing.T) { } }() + // Create ns-kube-system set + if err := ipsMgr.CreateSet("ns-" + util.KubeSystemFlag); err != nil { + t.Errorf("TestDeleteNetworkPolicy failed @ ipsMgr.CreateSet, adding kube-system set%+v", err) + } + nsObj := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: "test-nwpolicy", @@ -308,6 +323,6 @@ func TestDeleteNetworkPolicy(t *testing.T) { } if err := npMgr.DeleteNetworkPolicy(allow); err != nil { - t.Errorf("TestAddNetworkPolicy failed @ DeleteNetworkPolicy") + t.Errorf("TestDeleteNetworkPolicy failed @ DeleteNetworkPolicy") } } diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 200b81546a..7039fe51bb 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -2807,7 +2807,7 @@ func TestTranslatePolicy(t *testing.T) { }, } expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) - expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", targetSelector, false, true)...) + expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", targetSelector, true, true)...) if !reflect.DeepEqual(iptEntries, expectedIptEntries) { t.Errorf("translatedPolicy failed @ k8s-example-policy policy comparison") marshalledIptEntries, _ := json.Marshal(iptEntries)