diff options
author | Ritu Sood <ritu.sood@intel.com> | 2018-11-10 03:54:15 +0000 |
---|---|---|
committer | Victor Morales <victor.morales@intel.com> | 2018-12-05 16:26:56 -0800 |
commit | a1abd829315d72adb258da20470eaa2445cf3e32 (patch) | |
tree | a1c2ae3e61490241b0a4c93f49acffd6d319a7a4 /src/k8splugin/plugins/network | |
parent | daf3a00798ee77e469cd89cb16ade818c50968f9 (diff) |
Add Network and OVN4NFV Plugins
This patch includes support for Network Objects through a new plugin.
It also add the first sub-module plugin for OVN4NFVK8s support.
Change-Id: Ia23c42d50f75a5206e1b6a04052c34e940518428
Signed-off-by: Ritu Sood <ritu.sood@intel.com>
Signed-off-by: Victor Morales <victor.morales@intel.com>
Issue-ID: MULTICLOUD-303
Diffstat (limited to 'src/k8splugin/plugins/network')
-rw-r--r-- | src/k8splugin/plugins/network/plugin.go | 95 | ||||
-rw-r--r-- | src/k8splugin/plugins/network/plugin_test.go | 172 | ||||
-rw-r--r-- | src/k8splugin/plugins/network/v1/types.go | 67 |
3 files changed, 334 insertions, 0 deletions
diff --git a/src/k8splugin/plugins/network/plugin.go b/src/k8splugin/plugins/network/plugin.go new file mode 100644 index 00000000..d54fc429 --- /dev/null +++ b/src/k8splugin/plugins/network/plugin.go @@ -0,0 +1,95 @@ +/* +Copyright 2018 Intel Corporation. +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 ( + pkgerrors "github.com/pkg/errors" + "k8s.io/client-go/kubernetes" + "k8splugin/krd" + "k8splugin/plugins/network/v1" + "regexp" +) + +func extractData(data string) (vnfID, cniType, networkName string) { + re := regexp.MustCompile("_") + split := re.Split(data, -1) + if len(split) != 3 { + return + } + vnfID = split[0] + cniType = split[1] + networkName = split[2] + return +} + +// Create an ONAP Network object +func Create(data *krd.ResourceData, client kubernetes.Interface) (string, error) { + network := &v1.OnapNetwork{} + if _, err := krd.DecodeYAML(data.YamlFilePath, network); err != nil { + return "", pkgerrors.Wrap(err, "Decode network object error") + } + + config, err := network.DecodeConfig() + if err != nil { + return "", pkgerrors.Wrap(err, "Fail to decode network's configuration") + } + + cniType := config["cnitype"].(string) + typePlugin, ok := krd.LoadedPlugins[cniType+"-network"] + if !ok { + return "", pkgerrors.New("No plugin for resource " + cniType + " found") + } + + symCreateNetworkFunc, err := typePlugin.Lookup("CreateNetwork") + if err != nil { + return "", pkgerrors.Wrap(err, "Error fetching "+cniType+" plugin") + } + + name, err := symCreateNetworkFunc.(func(*v1.OnapNetwork) (string, error))(network) + if err != nil { + return "", pkgerrors.Wrap(err, "Error during the creation for "+cniType+" plugin") + } + + return data.VnfId + "_" + cniType + "_" + name, nil +} + +// List of Networks +func List(namespace string, kubeclient kubernetes.Interface) ([]string, error) { + return nil, nil +} + +// Delete an existing Network +func Delete(name string, namespace string, kubeclient kubernetes.Interface) error { + _, cniType, networkName := extractData(name) + typePlugin, ok := krd.LoadedPlugins[cniType+"-network"] + if !ok { + return pkgerrors.New("No plugin for resource " + cniType + " found") + } + + symDeleteNetworkFunc, err := typePlugin.Lookup("DeleteNetwork") + if err != nil { + return pkgerrors.Wrap(err, "Error fetching "+cniType+" plugin") + } + + if err := symDeleteNetworkFunc.(func(string) error)(networkName); err != nil { + return pkgerrors.Wrap(err, "Error during the deletion for "+cniType+" plugin") + } + + return nil +} + +// Get an existing Network +func Get(name string, namespace string, kubeclient kubernetes.Interface) (string, error) { + return "", nil +} diff --git a/src/k8splugin/plugins/network/plugin_test.go b/src/k8splugin/plugins/network/plugin_test.go new file mode 100644 index 00000000..325de31f --- /dev/null +++ b/src/k8splugin/plugins/network/plugin_test.go @@ -0,0 +1,172 @@ +// +build integration + +/* +Copyright 2018 Intel Corporation. +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 ( + pkgerrors "github.com/pkg/errors" + "k8splugin/krd" + "os" + "plugin" + "reflect" + "strings" + "testing" +) + +func LoadMockNetworkPlugins(krdLoadedPlugins *map[string]*plugin.Plugin, networkName, errMsg string) error { + if _, err := os.Stat("../../mock_files/mock_plugins/mocknetworkplugin.so"); os.IsNotExist(err) { + return pkgerrors.New("mocknetworkplugin.so does not exist. Please compile mocknetworkplugin.go to generate") + } + + mockNetworkPlugin, err := plugin.Open("../../mock_files/mock_plugins/mocknetworkplugin.so") + if err != nil { + return pkgerrors.Cause(err) + } + + symErrVar, err := mockNetworkPlugin.Lookup("Err") + if err != nil { + return err + } + symNetworkNameVar, err := mockNetworkPlugin.Lookup("NetworkName") + if err != nil { + return err + } + + *symErrVar.(*string) = errMsg + *symNetworkNameVar.(*string) = networkName + (*krdLoadedPlugins)["ovn4nfvk8s-network"] = mockNetworkPlugin + + return nil +} + +func TestCreateNetwork(t *testing.T) { + internalVNFID := "1" + oldkrdPluginData := krd.LoadedPlugins + + defer func() { + krd.LoadedPlugins = oldkrdPluginData + }() + + testCases := []struct { + label string + input *krd.ResourceData + mockError string + mockOutput string + expectedResult string + expectedError string + }{ + { + label: "Fail to decode a network object", + input: &krd.ResourceData{ + YamlFilePath: "../../mock_files/mock_yamls/service.yaml", + }, + expectedError: "Fail to decode network's configuration: Invalid configuration value", + }, + { + label: "Fail to create a network", + input: &krd.ResourceData{ + YamlFilePath: "../../mock_files/mock_yamls/ovn4nfvk8s.yaml", + }, + mockError: "Internal error", + expectedError: "Error during the creation for ovn4nfvk8s plugin: Internal error", + }, + { + label: "Successfully create a ovn4nfv network", + input: &krd.ResourceData{ + VnfId: internalVNFID, + YamlFilePath: "../../mock_files/mock_yamls/ovn4nfvk8s.yaml", + }, + expectedResult: internalVNFID + "_ovn4nfvk8s_myNetwork", + mockOutput: "myNetwork", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + err := LoadMockNetworkPlugins(&krd.LoadedPlugins, testCase.mockOutput, testCase.mockError) + if err != nil { + t.Fatalf("TestCreateNetwork returned an error (%s)", err) + } + result, err := Create(testCase.input, nil) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("Create method return an un-expected (%s)", err) + } + if !strings.Contains(string(err.Error()), testCase.expectedError) { + t.Fatalf("Create method returned an error (%s)", err) + } + } else { + if testCase.expectedError != "" && testCase.expectedResult == "" { + t.Fatalf("Create method was expecting \"%s\" error message", testCase.expectedError) + } + if !reflect.DeepEqual(testCase.expectedResult, result) { + + t.Fatalf("Create method returned: \n%v\n and it was expected: \n%v", result, testCase.expectedResult) + } + } + }) + } +} + +func TestDeleteNetwork(t *testing.T) { + oldkrdPluginData := krd.LoadedPlugins + + defer func() { + krd.LoadedPlugins = oldkrdPluginData + }() + + testCases := []struct { + label string + input string + mockError string + mockOutput string + expectedResult string + expectedError string + }{ + { + label: "Fail to load non-existing plugin", + input: "test", + expectedError: "No plugin for resource", + }, + { + label: "Fail to delete a network", + input: "1_ovn4nfvk8s_test", + mockError: "Internal error", + expectedError: "Error during the deletion for ovn4nfvk8s plugin: Internal error", + }, + { + label: "Successfully delete a ovn4nfv network", + input: "1_ovn4nfvk8s_test", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + err := LoadMockNetworkPlugins(&krd.LoadedPlugins, testCase.mockOutput, testCase.mockError) + if err != nil { + t.Fatalf("TestDeleteNetwork returned an error (%s)", err) + } + err = Delete(testCase.input, "", nil) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("Create method return an un-expected (%s)", err) + } + if !strings.Contains(string(err.Error()), testCase.expectedError) { + t.Fatalf("Create method returned an error (%s)", err) + } + } + }) + } +} diff --git a/src/k8splugin/plugins/network/v1/types.go b/src/k8splugin/plugins/network/v1/types.go new file mode 100644 index 00000000..b4efa39a --- /dev/null +++ b/src/k8splugin/plugins/network/v1/types.go @@ -0,0 +1,67 @@ +/* +Copyright 2018 Intel Corporation. +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 v1 + +import ( + "encoding/json" + + pkgerrors "github.com/pkg/errors" + metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// OnapNetwork describes an ONAP network resouce +type OnapNetwork struct { + metaV1.TypeMeta `json:",inline"` + metaV1.ObjectMeta `json:"metadata,omitempty"` + Spec OnapNetworkSpec `json:"spec"` +} + +// OnapNetworkSpec is the spec for OnapNetwork resource +type OnapNetworkSpec struct { + Config string `json:"config"` +} + +// DeepCopyObject returns a generically typed copy of an object +func (in OnapNetwork) DeepCopyObject() runtime.Object { + out := OnapNetwork{} + out.TypeMeta = in.TypeMeta + out.ObjectMeta = in.ObjectMeta + out.Spec = in.Spec + + return &out +} + +// GetObjectKind +func (in OnapNetwork) GetObjectKind() schema.ObjectKind { + return &in.TypeMeta +} + +// DecodeConfig content +func (in OnapNetwork) DecodeConfig() (map[string]interface{}, error) { + var raw map[string]interface{} + + if in.Spec.Config == "" { + return nil, pkgerrors.New("Invalid configuration value") + } + + if err := json.Unmarshal([]byte(in.Spec.Config), &raw); err != nil { + return nil, pkgerrors.Wrap(err, "JSON unmarshalling error") + } + + return raw, nil +} |