Skip to content

Commit

Permalink
Merge pull request #4124 from EdDev/tests-libnet
Browse files Browse the repository at this point in the history
tests, libnet: Move helpers into libnet
  • Loading branch information
kubevirt-bot committed Oct 3, 2020
2 parents 5029faf + cf0ae7d commit 0c0c443
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 45 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ require (
kubevirt.io/containerized-data-importer v1.23.5
kubevirt.io/qe-tools v0.1.6
libvirt.org/libvirt-go v6.5.0+incompatible
sigs.k8s.io/yaml v1.2.0
)

replace (
Expand Down
2 changes: 2 additions & 0 deletions tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ go_library(
"//staging/src/kubevirt.io/client-go/log:go_default_library",
"//tests/containerdisk:go_default_library",
"//tests/flags:go_default_library",
"//tests/libnet:go_default_library",
"//tests/libvmi:go_default_library",
"//tools/vms-generator/utils:go_default_library",
"//vendor/github.com/Masterminds/semver:go_default_library",
"//vendor/github.com/google/go-github/v32/github:go_default_library",
Expand Down
8 changes: 7 additions & 1 deletion tests/libnet/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["cluster.go"],
srcs = [
"cloudinit.go",
"cluster.go",
"dns.go",
"validation.go",
],
importpath = "kubevirt.io/kubevirt/tests/libnet",
visibility = ["//visibility:public"],
deps = [
Expand All @@ -12,5 +17,6 @@ go_library(
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/utils/net:go_default_library",
"//vendor/sigs.k8s.io/yaml:go_default_library",
],
)
104 changes: 104 additions & 0 deletions tests/libnet/cloudinit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* This file is part of the KubeVirt project
*
* 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.
*
* Copyright 2020 Red Hat, Inc.
*
*/

package libnet

import (
"sigs.k8s.io/yaml"
)

type CloudInitNetworkData struct {
Version int `yaml:"version"`
Ethernets map[string]CloudInitInterface `yaml:"ethernets,omitempty"`
}

type CloudInitInterface struct {
AcceptRA *bool `yaml:"accept-ra,omitempty"`
Addresses []string `yaml:"addresses,omitempty"`
DHCP4 *bool `yaml:"dhcp4,omitempty"`
DHCP6 *bool `yaml:"dhcp6,omitempty"`
DHCPIdentifier string `yaml:"dhcp-identifier,omitempty"` // "duid" or "mac"
Gateway4 string `yaml:"gateway4,omitempty"`
Gateway6 string `yaml:"gateway6,omitempty"`
Nameservers CloudInitNameservers `yaml:"nameservers,omitempty"`
MACAddress string `yaml:"macaddress,omitempty"`
MTU int `yaml:"mtu,omitempty"`
Routes []CloudInitRoute `yaml:"routes,omitempty"`
}

type CloudInitNameservers struct {
Search []string `yaml:"search,omitempty,flow"`
Addresses []string `yaml:"addresses,omitempty,flow"`
}

type CloudInitRoute struct {
From string `yaml:"from,omitempty"`
OnLink *bool `yaml:"on-link,omitempty"`
Scope string `yaml:"scope,omitempty"`
Table *int `yaml:"table,omitempty"`
To string `yaml:"to,omitempty"`
Type string `yaml:"type,omitempty"`
Via string `yaml:"via,omitempty"`
Metric *int `yaml:"metric,omitempty"`
}

const (
ipv6MasqueradeAddress = "fd10:0:2::2/120"
ipv6MasqueradeGateway = "fd10:0:2::1"
)

// CreateDefaultCloudInitNetworkData generates a default configuration
// for the Cloud-Init Network Data, in version 2 format.
// The default configuration sets dynamic IPv4 (DHCP) and static IPv6 addresses,
// inclusing DNS settings of the cluster nameserver IP and search domains.
func CreateDefaultCloudInitNetworkData() (string, error) {
dnsServerIP, err := ClusterDNSServiceIP()
if err != nil {
return "", err
}

enabled := true
networkData, err := CreateCloudInitNetworkData(
&CloudInitNetworkData{
Version: 2,
Ethernets: map[string]CloudInitInterface{
"eth0": {
Addresses: []string{ipv6MasqueradeAddress},
DHCP4: &enabled,
Gateway6: ipv6MasqueradeGateway,
Nameservers: CloudInitNameservers{
Addresses: []string{dnsServerIP},
Search: SearchDomains(),
},
},
},
},
)
if err != nil {
return "", err
}

return string(networkData), nil
}

// CreateCloudInitNetworkData generates a configuration for the Cloud-Init Network Data version 2 format
// based on the inputed data.
func CreateCloudInitNetworkData(networkData *CloudInitNetworkData) ([]byte, error) {
return yaml.Marshal(networkData)
}
60 changes: 60 additions & 0 deletions tests/libnet/dns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* This file is part of the KubeVirt project
*
* 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.
*
* Copyright 2020 Red Hat, Inc.
*
*/

package libnet

import (
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"kubevirt.io/client-go/kubecli"
)

const (
k8sDNSServiceName = "kube-dns"
k8sDNSNamespace = "kube-system"

openshiftDNSServiceName = "dns-default"
openshiftDNSNamespace = "openshift-dns"
)

// SearchDomains returns a list of default search name domains.
func SearchDomains() []string {
return []string{"default.svc.cluster.local", "svc.cluster.local", "cluster.local"}
}

// ClusterDNSServiceIP returns the cluster IP address of the DNS service.
// Attempts first to detect the DNS service on a k8s cluster and if not found on an openshift cluster.
func ClusterDNSServiceIP() (string, error) {
virtClient, err := kubecli.GetKubevirtClient()
if err != nil {
return "", err
}

service, err := virtClient.CoreV1().Services(k8sDNSNamespace).Get(k8sDNSServiceName, metav1.GetOptions{})
if err != nil {
prevErr := err
service, err = virtClient.CoreV1().Services(openshiftDNSNamespace).Get(openshiftDNSServiceName, metav1.GetOptions{})
if err != nil {
return "", fmt.Errorf("unable to detect the DNS services: %v, %v", prevErr, err)
}
}
return service.Spec.ClusterIP, nil
}
2 changes: 1 addition & 1 deletion tests/network/validation.go → tests/libnet/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*
*/

package network
package libnet

import (
"fmt"
Expand Down
16 changes: 16 additions & 0 deletions tests/libvmi/cloudinit.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ func WithCloudInitNoCloudUserData(data string, b64Encoding bool) Option {
}
}

// WithCloudInitNoCloudNetworkData adds cloud-init no-cloud network data.
func WithCloudInitNoCloudNetworkData(data string, b64Encoding bool) Option {
return func(vmi *kvirtv1.VirtualMachineInstance) {
diskName, bus := "disk1", "virtio"
addDiskVolumeWithCloudInitNoCloud(vmi, diskName, bus)

volume := getVolume(vmi, diskName)
if b64Encoding {
encodedData := base64.StdEncoding.EncodeToString([]byte(data))
volume.CloudInitNoCloud.NetworkDataBase64 = encodedData
} else {
volume.CloudInitNoCloud.NetworkData = data
}
}
}

func addDiskVolumeWithCloudInitNoCloud(vmi *kvirtv1.VirtualMachineInstance, diskName, bus string) {
addDisk(vmi, newDisk(diskName, bus))
v := newVolume(diskName)
Expand Down
2 changes: 1 addition & 1 deletion tests/libvmi/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func NewFedora(opts ...Option) *kvirtv1.VirtualMachineInstance {
WithResourceMemory("512M"),
WithRng(),
WithContainerImage(cd.ContainerDiskFor(cd.ContainerDiskFedora)),
WithCloudInitNoCloudUserData(configurePassword, true),
WithCloudInitNoCloudUserData(configurePassword, false),
)
opts = append(fedoraOptions, opts...)
return New(RandName(DefaultVmiName), opts...)
Expand Down
6 changes: 3 additions & 3 deletions tests/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import (
"kubevirt.io/kubevirt/tests"
cd "kubevirt.io/kubevirt/tests/containerdisk"
"kubevirt.io/kubevirt/tests/flags"
"kubevirt.io/kubevirt/tests/network"
"kubevirt.io/kubevirt/tests/libnet"
)

const (
Expand Down Expand Up @@ -519,7 +519,7 @@ var _ = Describe("[Serial][rfe_id:393][crit:high][vendor:cnv-qe@redhat.com][leve
newvmi, err := virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Get(vmi.Name, &metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred(), "Should successfully get new VMI")
vmiPod := tests.GetRunningPodByVirtualMachineInstance(newvmi, newvmi.Namespace)
return network.ValidateVMIandPodIPMatch(newvmi, vmiPod)
return libnet.ValidateVMIandPodIPMatch(newvmi, vmiPod)
}, 180*time.Second, time.Second).Should(Succeed(), "Should have updated IP and IPs fields")
}
// delete VMI
Expand Down Expand Up @@ -1972,7 +1972,7 @@ var _ = Describe("[Serial][rfe_id:393][crit:high][vendor:cnv-qe@redhat.com][leve
newvmi, err := virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Get(vmi.Name, &metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred(), "Should successfully get new VMI")
vmiPod := tests.GetRunningPodByVirtualMachineInstance(newvmi, newvmi.Namespace)
return network.ValidateVMIandPodIPMatch(newvmi, vmiPod)
return libnet.ValidateVMIandPodIPMatch(newvmi, vmiPod)
}, time.Minute, time.Second).Should(Succeed(), "Should match PodIP with latest VMI Status after migration")
}
})
Expand Down
1 change: 0 additions & 1 deletion tests/network/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ go_library(
"framework.go",
"primary_pod_network.go",
"services.go",
"validation.go",
],
importpath = "kubevirt.io/kubevirt/tests/network",
visibility = ["//visibility:public"],
Expand Down
3 changes: 2 additions & 1 deletion tests/network/primary_pod_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (

"kubevirt.io/kubevirt/tests"
cd "kubevirt.io/kubevirt/tests/containerdisk"
"kubevirt.io/kubevirt/tests/libnet"
)

var _ = SIGDescribe("[Serial]Primary Pod Network", func() {
Expand All @@ -50,7 +51,7 @@ var _ = SIGDescribe("[Serial]Primary Pod Network", func() {
vmiPod := tests.GetRunningPodByVirtualMachineInstance(vmi, tests.NamespaceTestDefault)

By("Making sure IP/s reported on the VMI matches the ones on the pod")
Expect(ValidateVMIandPodIPMatch(vmi, vmiPod)).To(Succeed(), "Should have matching IP/s between pod and vmi")
Expect(libnet.ValidateVMIandPodIPMatch(vmi, vmiPod)).To(Succeed(), "Should have matching IP/s between pod and vmi")
}

Context("VMI connected to the pod network using the default (implicit) binding", func() {
Expand Down
45 changes: 8 additions & 37 deletions tests/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ import (

cd "kubevirt.io/kubevirt/tests/containerdisk"
"kubevirt.io/kubevirt/tests/flags"
"kubevirt.io/kubevirt/tests/libnet"
"kubevirt.io/kubevirt/tests/libvmi"

"github.com/Masterminds/semver"
"github.com/google/go-github/v32/github"
Expand Down Expand Up @@ -223,11 +225,6 @@ const (
tmpPath = "/var/provision/kubevirt.io/tests"
)

const (
ipv6MasqueradeAddress = "fd10:0:2::2/120"
ipv6MasqueradeGateway = "fd10:0:2::1"
)

const (
capNetAdmin k8sv1.Capability = "NET_ADMIN"
capNetRaw k8sv1.Capability = "NET_RAW"
Expand Down Expand Up @@ -2134,18 +2131,13 @@ func AddEphemeralCdrom(vmi *v1.VirtualMachineInstance, name string, bus string,
}

func NewRandomFedoraVMIWitGuestAgent() *v1.VirtualMachineInstance {
virtClient, err := kubecli.GetKubevirtClient()
PanicOnError(err)

dnsServerIP, err := getClusterDnsServiceIP(virtClient)
PanicOnError(err)

searchDomains := getVMISeachDomains()
networkData := GetCloudInitNetworkData(ipv6MasqueradeAddress, ipv6MasqueradeGateway, dnsServerIP, searchDomains)
networkData, err := libnet.CreateDefaultCloudInitNetworkData()
Expect(err).NotTo(HaveOccurred())

agentVMI := NewRandomVMIWithEphemeralDiskAndUserdataNetworkData(cd.ContainerDiskFor(cd.ContainerDiskFedora), GetGuestAgentUserData(), networkData, false)
agentVMI.Spec.Domain.Resources.Requests[k8sv1.ResourceMemory] = resource.MustParse("512M")
return agentVMI
return libvmi.NewFedora(
libvmi.WithCloudInitNoCloudUserData(GetGuestAgentUserData(), false),
libvmi.WithCloudInitNoCloudNetworkData(networkData, false),
)
}

func AddPVCFS(vmi *v1.VirtualMachineInstance, name string, claimName string) *v1.VirtualMachineInstance {
Expand Down Expand Up @@ -2230,27 +2222,6 @@ func GetGuestAgentUserData() string {
`, guestAgentUrl, guestAgentUrl, GetUrl(StressHttpUrl))
}

// Returns NetworkData for configuring a dynamic IPv4 address, and a static
//IPv6 address, along with DNS configuration.
func GetCloudInitNetworkData(ipAddress string, gateway string, dnsServer string, searchDomains []string) string {
networkData := fmt.Sprintf(`
version: 2
ethernets:
eth0:
addresses: [ %s ]
dhcp4: true
gateway6: %s
nameservers:
addresses: [ %s ]
search: [ %s ]
`, ipAddress, gateway, dnsServer, strings.Join(searchDomains, " "))
return networkData
}

func getVMISeachDomains() []string {
return []string{"default.svc.cluster.local", "svc.cluster.local", "cluster.local"}
}

func NewRandomVMIWithEphemeralDiskAndUserdata(containerImage string, userData string) *v1.VirtualMachineInstance {
vmi := NewRandomVMIWithEphemeralDisk(containerImage)
AddUserData(vmi, "disk1", userData)
Expand Down

0 comments on commit 0c0c443

Please sign in to comment.