rook: Move network util functions to k8sutil

rook: Remove NetworkSelector type alias

rook: Add error return value for multus funcs

Signed-off-by: giovanism <giovanism@outlook.co.id>
This commit is contained in:
giovanism
2019-08-26 16:17:04 +07:00
parent cc62702d39
commit 4974be4b20
14 changed files with 292 additions and 212 deletions
-93
View File
@@ -16,13 +16,6 @@ limitations under the License.
package v1alpha2
import (
"encoding/json"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// IsHost get whether to use host network provider
func (net *NetworkSpec) IsHost() bool {
return net.Provider == "host"
@@ -32,89 +25,3 @@ func (net *NetworkSpec) IsHost() bool {
func (net *NetworkSpec) IsMultus() bool {
return net.Provider == "multus"
}
// parseMultusSelector will parse short and JSON form of individual multus
// network attachment selection annotation. Valid JSON will be unmarshaled and
// return as is, while invalid JSON will be tried using
// <namespace>/<name>@<interface> short syntax.
// BUG(giovanism): There are no data (name, interface, namespace) validation
func parseMultusSelector(ns NetworkSelector) map[string]string {
rawMap := make(map[string]string)
err := json.Unmarshal([]byte(ns), &rawMap)
if err != nil {
// it can be in short form
multusSelectorString := string(ns)
nsEndIndex := strings.IndexAny(multusSelectorString, "/")
if nsEndIndex != -1 {
rawMap["namespace"] = multusSelectorString[:nsEndIndex]
}
ifStartIndex := strings.LastIndexAny(multusSelectorString, "@")
if ifStartIndex != -1 && len(multusSelectorString)-ifStartIndex > 1 {
rawMap["interface"] = multusSelectorString[ifStartIndex+1:]
}
if nsEndIndex != -1 && ifStartIndex != -1 && ifStartIndex-nsEndIndex > 1 {
rawMap["name"] = multusSelectorString[nsEndIndex+1 : ifStartIndex]
} else if nsEndIndex == -1 && ifStartIndex != -1 {
rawMap["name"] = multusSelectorString[:ifStartIndex]
} else if nsEndIndex != -1 && ifStartIndex == -1 {
rawMap["name"] = multusSelectorString[nsEndIndex+1:]
}
}
return rawMap
}
// GetMultusIfName return a network interface name that multus will assign when
// connected to the multus network.
// BUG(giovanism): Can't relliably tell the network interface name using a
// network selector alone if the interface name is omitted.
func GetMultusIfName(ns NetworkSelector) string {
multusMap := parseMultusSelector(ns)
ifName := "net1"
if name, ok := multusMap["interfaceRequest"]; ok {
ifName = name
}
if name, ok := multusMap["interface"]; ok {
ifName = name
}
return ifName
}
// ApplyMultus apply multus selector to Pods
// Multus supports short and json syntax, use only one kind at a time.
// BUG(giovanism): Can't mix short and JSON form of multus network selection
// annotation.
func ApplyMultus(net NetworkSpec, objectMeta *metav1.ObjectMeta) {
v := make([]string, 0, 2)
useSquareBrackets := false
for _, ns := range net.Selectors {
if !useSquareBrackets {
var multusMap map[string]string
err := json.Unmarshal([]byte(ns), &multusMap)
if err == nil {
useSquareBrackets = true
}
}
v = append(v, string(ns))
}
networks := strings.Join(v, ", ")
if useSquareBrackets {
networks = "[" + networks + "]"
}
t := Annotations{
"k8s.v1.cni.cncf.io/networks": networks,
}
t.ApplyToObjectMeta(objectMeta)
}
+3 -83
View File
@@ -22,7 +22,6 @@ import (
"github.com/ghodss/yaml"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestNetwork_Spec(t *testing.T) {
@@ -42,90 +41,11 @@ selectors:
expected := NetworkSpec{
Provider: "host",
Selectors: map[string]NetworkSelector{
"server": NetworkSelector("enp2s0f0"),
"broker": NetworkSelector("enp2s0f0"),
Selectors: map[string]string{
"server": "enp2s0f0",
"broker": "enp2s0f0",
},
}
assert.Equal(t, expected, net)
}
func TestNetwork_GetMultusIfName(t *testing.T) {
multusSelector := NetworkSelector("macvlan@server1")
ifName := GetMultusIfName(multusSelector)
assert.Equal(t, "server1", ifName)
}
func TestNetwork_GetMultusIfNameDefault(t *testing.T) {
multusSelector := NetworkSelector("macvlan")
ifName := GetMultusIfName(multusSelector)
assert.Equal(t, "net1", ifName)
}
func TestNetwork_parseMultusSelectorJSON(t *testing.T) {
multusSelector := NetworkSelector(`{
"name": "macvlan",
"interface": "server1",
"namespace": "rook-edgefs"
}`)
multusMap := parseMultusSelector(multusSelector)
expected := map[string]string{
"name": "macvlan",
"interface": "server1",
"namespace": "rook-edgefs",
}
assert.Equal(t, expected, multusMap)
}
func TestNetwork_parseMultusSelectorShort(t *testing.T) {
multusSelector := NetworkSelector("rook-edgefs/macvlan@server1")
multusMap := parseMultusSelector(multusSelector)
expected := map[string]string{
"name": "macvlan",
"interface": "server1",
"namespace": "rook-edgefs",
}
assert.Equal(t, expected, multusMap)
}
func TestNetwork_ApplyMultusShort(t *testing.T) {
net := NetworkSpec{
Provider: "multus",
Selectors: map[string]NetworkSelector{
"server": "macvlan@net1",
"broker": "macvlan@net2",
},
}
objMeta := metav1.ObjectMeta{}
ApplyMultus(net, &objMeta)
assert.Contains(t, objMeta.Annotations, "k8s.v1.cni.cncf.io/networks")
assert.Contains(t, objMeta.Annotations["k8s.v1.cni.cncf.io/networks"], "macvlan@net1")
assert.Contains(t, objMeta.Annotations["k8s.v1.cni.cncf.io/networks"], "macvlan@net2")
}
func TestNetwork_ApplyMultusJSON(t *testing.T) {
net := NetworkSpec{
Provider: "multus",
Selectors: map[string]NetworkSelector{
"server": `{"name": "macvlan", "interface": "net1"}`,
"broker": `{"name": "macvlan", "interface": "net2"}`,
},
}
objMeta := metav1.ObjectMeta{}
ApplyMultus(net, &objMeta)
assert.Contains(t, objMeta.Annotations, "k8s.v1.cni.cncf.io/networks")
assert.Contains(t, objMeta.Annotations["k8s.v1.cni.cncf.io/networks"], `{"name": "macvlan", "interface": "net1"}`)
assert.Contains(t, objMeta.Annotations["k8s.v1.cni.cncf.io/networks"], `{"name": "macvlan", "interface": "net2"}`)
}
+1 -3
View File
@@ -81,8 +81,6 @@ type Placement struct {
type ResourceSpec map[string]v1.ResourceRequirements
type NetworkSelector string
// NetworkSpec represents cluster network settings
type NetworkSpec struct {
// Provider is what provides network connectivity to the cluster e.g. "host" or "multus"
@@ -91,7 +89,7 @@ type NetworkSpec struct {
// Selectors string values describe what networks will be used to connect the cluster.
// Meanwhile the keys describe each network respective responsibilities or any metadata
// storage provider decide.
Selectors map[string]NetworkSelector `json:"selectors"`
Selectors map[string]string `json:"selectors"`
}
// +genclient
@@ -146,7 +146,7 @@ func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) {
*out = *in
if in.Selectors != nil {
in, out := &in.Selectors, &out.Selectors
*out = make(map[string]NetworkSelector, len(*in))
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
+32 -19
View File
@@ -20,7 +20,6 @@ import (
"encoding/json"
edgefsv1beta1 "github.com/rook/rook/pkg/apis/edgefs.rook.io/v1beta1"
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
"github.com/rook/rook/pkg/operator/edgefs/cluster/target"
"github.com/rook/rook/pkg/operator/k8sutil"
v1 "k8s.io/api/core/v1"
@@ -49,33 +48,47 @@ func (c *cluster) createClusterConfigMap(deploymentConfig edgefsv1beta1.ClusterD
serverIfName := defaultServerIfName
brokerIfName := defaultBrokerIfName
if c.Spec.Network.IsHost() {
serverSelector, serverDefined := c.Spec.Network.Selectors["server"]
brokerSelector, brokerDefined := c.Spec.Network.Selectors["broker"]
serverSelector, serverDefined := c.Spec.Network.Selectors["server"]
brokerSelector, brokerDefined := c.Spec.Network.Selectors["broker"]
if c.Spec.Network.IsHost() {
if serverDefined && brokerDefined {
serverIfName = string(serverSelector)
brokerIfName = string(brokerSelector)
serverIfName = serverSelector
brokerIfName = brokerSelector
} else if serverDefined {
serverIfName = string(serverSelector)
brokerIfName = string(serverSelector)
serverIfName = serverSelector
brokerIfName = serverSelector
} else if brokerDefined {
serverIfName = string(brokerSelector)
brokerIfName = string(brokerSelector)
serverIfName = brokerSelector
brokerIfName = brokerSelector
}
} else if c.Spec.Network.IsMultus() {
serverSelector, serverDefined := c.Spec.Network.Selectors["server"]
brokerSelector, brokerDefined := c.Spec.Network.Selectors["broker"]
if serverDefined && brokerDefined {
serverIfName = rookalpha.GetMultusIfName(serverSelector)
brokerIfName = rookalpha.GetMultusIfName(brokerSelector)
var err error
serverIfName, err = k8sutil.GetMultusIfName(serverSelector)
if err != nil {
return err
}
brokerIfName, err = k8sutil.GetMultusIfName(brokerSelector)
if err != nil {
return err
}
} else if serverDefined {
serverIfName = rookalpha.GetMultusIfName(serverSelector)
brokerIfName = rookalpha.GetMultusIfName(serverSelector)
serverIfName, err := k8sutil.GetMultusIfName(serverSelector)
if err != nil {
return err
}
brokerIfName = serverIfName
} else if brokerDefined {
serverIfName = rookalpha.GetMultusIfName(brokerSelector)
brokerIfName = rookalpha.GetMultusIfName(brokerSelector)
serverIfName, err := k8sutil.GetMultusIfName(brokerSelector)
if err != nil {
return err
}
brokerIfName = serverIfName
}
}
+1 -1
View File
@@ -344,7 +344,7 @@ func (c *Cluster) makeDeployment(name, clusterName, rookImage string, replicas i
if c.NetworkSpec.IsHost() {
podSpec.Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
} else if c.NetworkSpec.IsMultus() {
rookalpha.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
k8sutil.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
}
c.annotations.ApplyToObjectMeta(&podSpec.ObjectMeta)
+1 -1
View File
@@ -122,7 +122,7 @@ func TestHostNetwork(t *testing.T) {
volSize := resource.NewQuantity(100000.0, resource.BinarySI)
net := rookalpha.NetworkSpec{
Provider: "host",
Selectors: map[string]rookalpha.NetworkSelector{
Selectors: map[string]string{
"server": "eth0",
},
}
+2 -3
View File
@@ -21,7 +21,6 @@ import (
"strconv"
edgefsv1beta1 "github.com/rook/rook/pkg/apis/edgefs.rook.io/v1beta1"
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
"github.com/rook/rook/pkg/operator/edgefs/cluster/target/config"
"github.com/rook/rook/pkg/operator/k8sutil"
appsv1 "k8s.io/api/apps/v1"
@@ -565,8 +564,8 @@ func (c *Cluster) makeStatefulSet(replicas int32, rookImage string, dro edgefsv1
k8sutil.SetOwnerRef(&statefulSet.ObjectMeta, &c.ownerRef)
if c.NetworkSpec.IsMultus() {
rookalpha.ApplyMultus(c.NetworkSpec, &statefulSet.ObjectMeta)
rookalpha.ApplyMultus(c.NetworkSpec, &statefulSet.Spec.Template.ObjectMeta)
k8sutil.ApplyMultus(c.NetworkSpec, &statefulSet.ObjectMeta)
k8sutil.ApplyMultus(c.NetworkSpec, &statefulSet.Spec.Template.ObjectMeta)
}
c.annotations.ApplyToObjectMeta(&statefulSet.ObjectMeta)
c.annotations.ApplyToObjectMeta(&statefulSet.Spec.Template.ObjectMeta)
+1 -2
View File
@@ -22,7 +22,6 @@ import (
"fmt"
edgefsv1beta1 "github.com/rook/rook/pkg/apis/edgefs.rook.io/v1beta1"
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
"github.com/rook/rook/pkg/clusterd"
"github.com/rook/rook/pkg/operator/k8sutil"
apps "k8s.io/api/apps/v1"
@@ -177,7 +176,7 @@ func (c *ISCSIController) makeDeployment(svcname, namespace, rookImage string, i
if c.NetworkSpec.IsHost() {
podSpec.Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
} else if c.NetworkSpec.IsMultus() {
rookalpha.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
k8sutil.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
}
iscsiSpec.Annotations.ApplyToObjectMeta(&podSpec.ObjectMeta)
+1 -2
View File
@@ -21,7 +21,6 @@ import (
"fmt"
edgefsv1beta1 "github.com/rook/rook/pkg/apis/edgefs.rook.io/v1beta1"
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
"github.com/rook/rook/pkg/clusterd"
"github.com/rook/rook/pkg/operator/k8sutil"
apps "k8s.io/api/apps/v1"
@@ -181,7 +180,7 @@ func (c *NFSController) makeDeployment(svcname, namespace, rookImage string, nfs
if c.NetworkSpec.IsHost() {
podSpec.Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
} else if c.NetworkSpec.IsMultus() {
rookalpha.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
k8sutil.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
}
nfsSpec.Annotations.ApplyToObjectMeta(&podSpec.ObjectMeta)
+1 -2
View File
@@ -22,7 +22,6 @@ import (
"strings"
edgefsv1beta1 "github.com/rook/rook/pkg/apis/edgefs.rook.io/v1beta1"
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
"github.com/rook/rook/pkg/clusterd"
"github.com/rook/rook/pkg/operator/k8sutil"
apps "k8s.io/api/apps/v1"
@@ -246,7 +245,7 @@ func (c *S3Controller) makeDeployment(svcname, namespace, rookImage, imageArgs s
if c.NetworkSpec.IsHost() {
podSpec.Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
} else if c.NetworkSpec.IsMultus() {
rookalpha.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
k8sutil.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
}
// apply current S3 CRD options to pod's specification
+1 -2
View File
@@ -22,7 +22,6 @@ import (
"strings"
edgefsv1beta1 "github.com/rook/rook/pkg/apis/edgefs.rook.io/v1beta1"
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
"github.com/rook/rook/pkg/clusterd"
"github.com/rook/rook/pkg/operator/k8sutil"
apps "k8s.io/api/apps/v1"
@@ -230,7 +229,7 @@ func (c *S3XController) makeDeployment(svcname, namespace, rookImage string, s3x
if c.NetworkSpec.IsHost() {
podSpec.Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
} else if c.NetworkSpec.IsMultus() {
rookalpha.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
k8sutil.ApplyMultus(c.NetworkSpec, &podSpec.ObjectMeta)
}
// apply current S3X CRD options to pod's specification
+121
View File
@@ -0,0 +1,121 @@
/*
Copyright 2019 The Rook Authors. All rights reserved.
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 k8sutil
import (
"encoding/json"
"fmt"
"strings"
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// parseMultusSelector will parse short and JSON form of individual multus
// network attachment selection annotation. Valid JSON will be unmarshaled and
// return as is, while invalid JSON will be tried using
// <namespace>/<name>@<interface> short syntax.
func parseMultusSelector(selector string) (map[string]string, error) {
rawMap := make(map[string]string)
err := json.Unmarshal([]byte(selector), &rawMap)
if err != nil {
// it can be in short form
nsEndIndex := strings.IndexAny(selector, "/")
if nsEndIndex != -1 {
rawMap["namespace"] = selector[:nsEndIndex]
}
ifStartIndex := strings.LastIndexAny(selector, "@")
if ifStartIndex != -1 && len(selector)-ifStartIndex > 1 {
rawMap["interface"] = selector[ifStartIndex+1:]
}
if nsEndIndex != -1 && ifStartIndex != -1 && ifStartIndex-nsEndIndex > 1 {
rawMap["name"] = selector[nsEndIndex+1 : ifStartIndex]
} else if nsEndIndex == -1 && ifStartIndex != -1 {
rawMap["name"] = selector[:ifStartIndex]
} else if nsEndIndex != -1 && ifStartIndex == -1 {
rawMap["name"] = selector[nsEndIndex+1:]
}
}
if name, ok := rawMap["name"]; !ok || name == "" {
return nil, fmt.Errorf("parseMultusSelector: missing name")
}
return rawMap, nil
}
// GetMultusIfName return a network interface name that multus will assign when
// connected to the multus network.
func GetMultusIfName(selector string) (string, error) {
multusMap, _ := parseMultusSelector(selector)
var ifName string
if name, ok := multusMap["interfaceRequest"]; ok {
ifName = name
}
if name, ok := multusMap["interface"]; ok {
ifName = name
}
// fail selector without inteface name
if ifName == "" {
return "", fmt.Errorf("GetMultusIfname: missing interface")
}
return ifName, nil
}
// ApplyMultus apply multus selector to Pods
// Multus supports short and json syntax, use only one kind at a time.
func ApplyMultus(net rookalpha.NetworkSpec, objectMeta *metav1.ObjectMeta) error {
v := make([]string, 0, 2)
shortSyntax := false
jsonSyntax := false
for _, ns := range net.Selectors {
var multusMap map[string]string
err := json.Unmarshal([]byte(ns), &multusMap)
if err == nil {
jsonSyntax = true
} else {
shortSyntax = true
}
v = append(v, string(ns))
}
if shortSyntax && jsonSyntax {
return fmt.Errorf("ApplyMultus: Can't mix short and JSON form")
}
networks := strings.Join(v, ", ")
if jsonSyntax {
networks = "[" + networks + "]"
}
t := rookalpha.Annotations{
"k8s.v1.cni.cncf.io/networks": networks,
}
t.ApplyToObjectMeta(objectMeta)
return nil
}
+126
View File
@@ -0,0 +1,126 @@
/*
Copyright 2019 The Rook Authors. All rights reserved.
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 k8sutil
import (
"testing"
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestNetwork_GetMultusIfName(t *testing.T) {
multusSelector := "macvlan@server1"
ifName, _ := GetMultusIfName(multusSelector)
assert.Equal(t, "server1", ifName)
}
func TestNetwork_GetMultusIfNameDefault(t *testing.T) {
multusSelector := "macvlan"
_, err := GetMultusIfName(multusSelector)
assert.Error(t, err)
}
func TestNetwork_parseMultusSelectorJSON(t *testing.T) {
multusSelector := `{
"name": "macvlan",
"interface": "server1",
"namespace": "rook-edgefs"
}`
multusMap, _ := parseMultusSelector(multusSelector)
expected := map[string]string{
"name": "macvlan",
"interface": "server1",
"namespace": "rook-edgefs",
}
assert.Equal(t, expected, multusMap)
}
func TestNetwork_parseMultusSelectorShort(t *testing.T) {
multusSelector := "rook-edgefs/macvlan@server1"
multusMap, _ := parseMultusSelector(multusSelector)
expected := map[string]string{
"name": "macvlan",
"interface": "server1",
"namespace": "rook-edgefs",
}
assert.Equal(t, expected, multusMap)
}
func TestNetwork_parseMultusSelectorError(t *testing.T) {
multusSelector := "rook-edgefs/@server1"
_, err := parseMultusSelector(multusSelector)
assert.Error(t, err)
}
func TestNetwork_ApplyMultusShort(t *testing.T) {
net := rookalpha.NetworkSpec{
Provider: "multus",
Selectors: map[string]string{
"server": "macvlan@net1",
"broker": "macvlan@net2",
},
}
objMeta := metav1.ObjectMeta{}
ApplyMultus(net, &objMeta)
assert.Contains(t, objMeta.Annotations, "k8s.v1.cni.cncf.io/networks")
assert.Contains(t, objMeta.Annotations["k8s.v1.cni.cncf.io/networks"], "macvlan@net1")
assert.Contains(t, objMeta.Annotations["k8s.v1.cni.cncf.io/networks"], "macvlan@net2")
}
func TestNetwork_ApplyMultusJSON(t *testing.T) {
net := rookalpha.NetworkSpec{
Provider: "multus",
Selectors: map[string]string{
"server": `{"name": "macvlan", "interface": "net1"}`,
"broker": `{"name": "macvlan", "interface": "net2"}`,
},
}
objMeta := metav1.ObjectMeta{}
ApplyMultus(net, &objMeta)
assert.Contains(t, objMeta.Annotations, "k8s.v1.cni.cncf.io/networks")
assert.Contains(t, objMeta.Annotations["k8s.v1.cni.cncf.io/networks"], `{"name": "macvlan", "interface": "net1"}`)
assert.Contains(t, objMeta.Annotations["k8s.v1.cni.cncf.io/networks"], `{"name": "macvlan", "interface": "net2"}`)
}
func TestNetwork_ApplyMultusMixedError(t *testing.T) {
net := rookalpha.NetworkSpec{
Provider: "multus",
Selectors: map[string]string{
"server": `{"name": "macvlan", "interface": "net1"}`,
"broker": `macvlan@net2`,
},
}
objMeta := metav1.ObjectMeta{}
err := ApplyMultus(net, &objMeta)
assert.Error(t, err)
}