diff --git a/config/crd/bases/req.nephio.org_datanetworks.yaml b/config/crd/bases/req.nephio.org_datanetworks.yaml index c61d63ea..c92f94b5 100644 --- a/config/crd/bases/req.nephio.org_datanetworks.yaml +++ b/config/crd/bases/req.nephio.org_datanetworks.yaml @@ -92,53 +92,55 @@ spec: status: properties: ipAllocationStatus: - description: IPAllocationStatus defines the observed state of IPAllocation - properties: - conditions: - description: Conditions of the resource. - items: - description: A Condition that may apply to a resource - properties: - kind: - description: Type of this condition. At most one of each - condition type may apply to a resource at any point in - time. - type: string - lastTransitionTime: - description: LastTransitionTime is the last time this condition - transitioned from one status to another. - format: date-time - type: string - message: - description: A Message containing details about this condition's - last transition from one status to another, if any. - type: string - reason: - description: A Reason for this condition's last transition - from one status to another. - type: string - status: - description: Status of this condition; is it currently True, - False, or Unknown? - type: string - required: - - kind - - lastTransitionTime - - reason - - status - type: object - type: array - expiryTime: - description: expiryTime indicated when the allocation expires - type: string - gateway: - description: Gateway identifies the gatway IP for the network - type: string - prefix: - description: AllocatedPrefix identifies the prefix that was allocated - by the IPAM system - type: string - type: object + items: + description: IPAllocationStatus defines the observed state of IPAllocation + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource + properties: + kind: + description: Type of this condition. At most one of each + condition type may apply to a resource at any point + in time. + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this + condition transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition + from one status to another. + type: string + status: + description: Status of this condition; is it currently + True, False, or Unknown? + type: string + required: + - kind + - lastTransitionTime + - reason + - status + type: object + type: array + expiryTime: + description: expiryTime indicated when the allocation expires + type: string + gateway: + description: Gateway identifies the gatway IP for the network + type: string + prefix: + description: AllocatedPrefix identifies the prefix that was + allocated by the IPAM system + type: string + type: object + type: array type: object type: object served: true diff --git a/go.mod b/go.mod index 7a3b60ff..e5fecf4f 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.20 require ( github.com/google/go-cmp v0.5.9 github.com/nokia/k8s-ipam v0.0.4-0.20230416191338-dcd944a8d636 - github.com/stretchr/testify v1.8.1 k8s.io/api v0.27.1 k8s.io/apimachinery v0.27.1 + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 sigs.k8s.io/controller-runtime v0.14.6 ) @@ -35,7 +35,6 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.15.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -57,7 +56,6 @@ require ( k8s.io/client-go v0.27.1 // indirect k8s.io/klog/v2 v2.90.1 // indirect k8s.io/kube-openapi v0.0.0-20230327201221-f5883ff37f0c // indirect - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index c4ab332e..2f666be7 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,5 +1,5 @@ /* -Copyright 2023 Nephio. +Copyright 2023 The Nephio Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/lcov.info b/lcov.info new file mode 100644 index 00000000..d04994f8 --- /dev/null +++ b/lcov.info @@ -0,0 +1,18 @@ +mode: set +github.com/nephio-project/api/nf_requirements/v1alpha1/capacity_interfaces.go:22.63,24.2 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/capacity_interfaces.go:27.65,29.2 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/capacity_interfaces.go:32.41,34.2 1 0 +github.com/nephio-project/api/nf_requirements/v1alpha1/capacity_interfaces.go:37.44,39.2 1 0 +github.com/nephio-project/api/nf_requirements/v1alpha1/dnn_interfaces.go:24.65,26.35 2 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/dnn_interfaces.go:26.35,29.3 2 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/dnn_interfaces.go:30.2,30.12 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/dnn_interfaces.go:34.42,35.25 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/dnn_interfaces.go:35.25,37.3 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/dnn_interfaces.go:38.2,38.21 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/dnn_interfaces.go:42.33,44.2 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/dnn_interfaces.go:47.40,49.2 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/interface_interfaces.go:43.63,45.35 2 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/interface_interfaces.go:45.35,48.3 2 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/interface_interfaces.go:49.2,49.12 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/interface_interfaces.go:53.42,55.2 1 1 +github.com/nephio-project/api/nf_requirements/v1alpha1/interface_interfaces.go:58.56,60.2 1 1 diff --git a/nf_deployments/v1alpha1/zz_generated.deepcopy.go b/nf_deployments/v1alpha1/zz_generated.deepcopy.go index 07b8a7ed..f0fb0290 100644 --- a/nf_deployments/v1alpha1/zz_generated.deepcopy.go +++ b/nf_deployments/v1alpha1/zz_generated.deepcopy.go @@ -2,7 +2,7 @@ // +build !ignore_autogenerated /* -Copyright 2023 Nephio. +Copyright 2023 The Nephio Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/nf_requirements/v1alpha1/capacity_interfaces.go b/nf_requirements/v1alpha1/capacity_interfaces.go new file mode 100644 index 00000000..bee2de4b --- /dev/null +++ b/nf_requirements/v1alpha1/capacity_interfaces.go @@ -0,0 +1,44 @@ +/* +Copyright 2023 The Nephio 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 v1alpha1 + +import "k8s.io/apimachinery/pkg/api/resource" + +// GetMaxUplinkThroughput return the max uplinkthroughput +func (r *Capacity) GetMaxUplinkThroughput() *resource.Quantity { + return r.Spec.MaxUplinkThroughput +} + +// GetMaxDownlinkThroughput return the max downlinkthroughput +func (r *Capacity) GetMaxDownlinkThroughput() *resource.Quantity { + return r.Spec.MaxDownlinkThroughput +} + +// GetMaxSessions returns the max sessions +func (r *Capacity) GetMaxSessions() *int { + return r.Spec.MaxSessions +} + +// GetMaxSubscribers returns the max subscribers +func (r *Capacity) GetMaxSubscribers() *int { + return r.Spec.MaxSubscribers +} + +// GetMaxNFConnections returns the max connections to a network function +func (r *Capacity) GetMaxNFConnections() *uint16 { + return r.Spec.MaxNFConnections +} diff --git a/nf_requirements/v1alpha1/capacity_test.go b/nf_requirements/v1alpha1/capacity_test.go new file mode 100644 index 00000000..06eb0bcc --- /dev/null +++ b/nf_requirements/v1alpha1/capacity_test.go @@ -0,0 +1,234 @@ +/* +Copyright 2023 The Nephio 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 v1alpha1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/api/resource" +) + +func TestCapacityGetMaxUplinkThroughput(t *testing.T) { + res := resource.MustParse("5G") + + tests := map[string]struct { + input Capacity + want *resource.Quantity + }{ + "TestGetMaxUplinkThroughputEmpty": { + input: Capacity{ + Spec: CapacitySpec{}, + }, + want: nil, + }, + "TestGetMaxUplinkThroughput": { + input: Capacity{ + Spec: CapacitySpec{ + MaxUplinkThroughput: &res, + }, + }, + want: &res, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := tc.input.GetMaxUplinkThroughput() + switch { + case got == nil && tc.want != nil: + t.Errorf("TestCapacityGetMaxUplinkThroughput: -want %v, +got: nil\n", *tc.want) + case got != nil && tc.want == nil: + t.Errorf("TestCapacityGetMaxUplinkThroughput: -want nil, +got: %v\n", *got) + case got != nil && tc.want != nil: + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("TestCapacityGetMaxUplinkThroughput: -want, +got:\n%s", diff) + } + default: + // got == nil and want == nil ok + } + }) + } +} + +func TestCapacityGetMaxDownlinkThroughput(t *testing.T) { + res := resource.MustParse("5G") + + tests := map[string]struct { + input Capacity + want *resource.Quantity + }{ + "TestGetMaxDownlinkThroughputEmpty": { + input: Capacity{ + Spec: CapacitySpec{}, + }, + want: nil, + }, + "TestGetMaxDownlinkThroughput": { + input: Capacity{ + Spec: CapacitySpec{ + MaxDownlinkThroughput: &res, + }, + }, + want: &res, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := tc.input.GetMaxDownlinkThroughput() + switch { + case got == nil && tc.want != nil: + t.Errorf("TestCapacityGetMaxDownlinkThroughput: -want %v, +got: nil\n", *tc.want) + case got != nil && tc.want == nil: + t.Errorf("TestCapacityGetMaxDownlinkThroughput: -want nil, +got: %v\n", *got) + case got != nil && tc.want != nil: + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("TestCapacityGetMaxDownlinkThroughput: -want, +got:\n%s", diff) + } + default: + // got == nil and want == nil ok + } + }) + } +} + +func TestCapacityGetMaxSessions(t *testing.T) { + maxSessions := 10 + + tests := map[string]struct { + input Capacity + want *int + }{ + "TestGetMaxSessionsEmpty": { + input: Capacity{ + Spec: CapacitySpec{}, + }, + want: nil, + }, + "TestGetMaxSessions": { + input: Capacity{ + Spec: CapacitySpec{ + MaxSessions: &maxSessions, + }, + }, + want: &maxSessions, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := tc.input.GetMaxSessions() + switch { + case got == nil && tc.want != nil: + t.Errorf("TestCapacityGetMaxSessions: -want %v, +got: nil\n", *tc.want) + case got != nil && tc.want == nil: + t.Errorf("TestCapacityGetMaxSessions: -want nil, +got: %v\n", *got) + case got != nil && tc.want != nil: + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("TestCapacityGetMaxSessions: -want, +got:\n%s", diff) + } + default: + // got == nil and want == nil ok + } + }) + } +} + +func TestCapacityGetMaxSubscribers(t *testing.T) { + maxSubscribers := 10 + + tests := map[string]struct { + input Capacity + want *int + }{ + "TestGetMaxSubscribersEmpty": { + input: Capacity{ + Spec: CapacitySpec{}, + }, + want: nil, + }, + "TestGetMaxSubscribers": { + input: Capacity{ + Spec: CapacitySpec{ + MaxSubscribers: &maxSubscribers, + }, + }, + want: &maxSubscribers, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := tc.input.GetMaxSubscribers() + switch { + case got == nil && tc.want != nil: + t.Errorf("TestCapacityGetMaxSubscribers: -want %v, +got: nil\n", *tc.want) + case got != nil && tc.want == nil: + t.Errorf("TestCapacityGetMaxSubscribers: -want nil, +got: %v\n", *got) + case got != nil && tc.want != nil: + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("TestCapacityGetMaxSubscribers: -want, +got:\n%s", diff) + } + default: + // got == nil and want == nil ok + } + }) + } +} + +func TestCapacityGetMaxNFConnections(t *testing.T) { + maxNFConnections := uint16(10) + + tests := map[string]struct { + input Capacity + want *uint16 + }{ + "TestCapacityGetMaxNFConnectionsEmpty": { + input: Capacity{ + Spec: CapacitySpec{}, + }, + want: nil, + }, + "TestCapacityGetMaxNFConnectionsNormal": { + input: Capacity{ + Spec: CapacitySpec{ + MaxNFConnections: &maxNFConnections, + }, + }, + want: &maxNFConnections, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := tc.input.GetMaxNFConnections() + switch { + case got == nil && tc.want != nil: + t.Errorf("TestCapacityGetMaxNFConnections: -want %v, +got: nil\n", *tc.want) + case got != nil && tc.want == nil: + t.Errorf("TestCapacityGetMaxNFConnections: -want nil, +got: %v\n", *got) + case got != nil && tc.want != nil: + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("TestCapacityGetMaxNFConnections: -want, +got:\n%s", diff) + } + default: + // got == nil and want == nil ok + } + }) + } +} diff --git a/nf_requirements/v1alpha1/capacity_types.go b/nf_requirements/v1alpha1/capacity_types.go index 3dd0820a..24bd63f9 100644 --- a/nf_requirements/v1alpha1/capacity_types.go +++ b/nf_requirements/v1alpha1/capacity_types.go @@ -35,17 +35,21 @@ type Capacity struct { type CapacitySpec struct { // MaxUplinkThroughput defines the max uplink dataplane throughput - MaxUplinkThroughput resource.Quantity `json:"maxUplinkThroughput,omitempty" yaml:"maxUplinkThroughput,omitempty"` + // +kubebuilder:validation:Optional + MaxUplinkThroughput *resource.Quantity `json:"maxUplinkThroughput,omitempty" yaml:"maxUplinkThroughput,omitempty"` // MaxDownlinkThroughput defines the max downlink dataplane throughput - MaxDownlinkThroughput resource.Quantity `json:"maxDownlinkThroughput,omitempty" yaml:"maxDownlinkThroughput,omitempty"` + // +kubebuilder:validation:Optional + MaxDownlinkThroughput *resource.Quantity `json:"maxDownlinkThroughput,omitempty" yaml:"maxDownlinkThroughput,omitempty"` // MaxSessions defines the max sessions of the control plane // expressed in unit of 1000s - MaxSessions int `json:"maxSessions,omitempty" yaml:"maxSessions,omitempty"` + // +kubebuilder:validation:Optional + MaxSessions *int `json:"maxSessions,omitempty" yaml:"maxSessions,omitempty"` // MaxSubscribers defines the max subscribers // expressed in unit of 1000s - MaxSubscribers int `json:"maxSubscribers,omitempty" yaml:"maxSubscribers,omitempty"` + // +kubebuilder:validation:Optional + MaxSubscribers *int `json:"maxSubscribers,omitempty" yaml:"maxSubscribers,omitempty"` // MaxNFConnections defines the max NF(s) that can be connected to this NF/device - MaxNFConnections uint16 `json:"maxNFConnections,omitempty" yaml:"maxNFConnections,omitempty"` + MaxNFConnections *uint16 `json:"maxNFConnections,omitempty" yaml:"maxNFConnections,omitempty"` } type CapacityStatus struct { diff --git a/nf_requirements/v1alpha1/dnn_interfaces.go b/nf_requirements/v1alpha1/dnn_interfaces.go new file mode 100644 index 00000000..c1a1e852 --- /dev/null +++ b/nf_requirements/v1alpha1/dnn_interfaces.go @@ -0,0 +1,49 @@ +/* +Copyright 2023 The Nephio 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 v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/types" +) + +// GetNetworkInstance returns the networkinstance of the dnn +func (r *DataNetwork) GetNetworkInstance() types.NamespacedName { + nsn := types.NamespacedName{} + if r.Spec.NetworkInstance != nil { + nsn.Name = r.Spec.NetworkInstance.Name + nsn.Namespace = r.Spec.NetworkInstance.Namespace + } + return nsn +} + +// GetPools return the pools fron the dnn +func (r *DataNetwork) GetPools() []Pool { + if r.Spec.Pools == nil { + return []Pool{} + } + return r.Spec.Pools +} + +// GetName return the pool name +func (r *Pool) GetName() *string { + return r.Name +} + +// GetPrefixLength returns the prefixlength of the pool +func (r *Pool) GetPrefixLength() uint8 { + return r.PrefixLength +} diff --git a/nf_requirements/v1alpha1/dnn_test.go b/nf_requirements/v1alpha1/dnn_test.go new file mode 100644 index 00000000..7b6fbcf7 --- /dev/null +++ b/nf_requirements/v1alpha1/dnn_test.go @@ -0,0 +1,166 @@ +/* +Copyright 2023 The Nephio 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 v1alpha1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/pointer" +) + +func TestDNNGetNetworkInstance(t *testing.T) { + tests := map[string]struct { + input DataNetwork + want types.NamespacedName + }{ + "GetNetworkInstanceEmpty": { + input: DataNetwork{ + Spec: DataNetworkSpec{}, + }, + want: types.NamespacedName{}, + }, + "GetNetworkInstanceName": { + input: DataNetwork{ + Spec: DataNetworkSpec{ + NetworkInstance: &corev1.ObjectReference{ + Name: "a", + }, + }, + }, + want: types.NamespacedName{ + Name: "a", + }, + }, + "GetNetworkInstanceNameSpace": { + input: DataNetwork{ + Spec: DataNetworkSpec{ + NetworkInstance: &corev1.ObjectReference{ + Namespace: "a", + }, + }, + }, + want: types.NamespacedName{ + Namespace: "a", + }, + }, + "GetNetworkInstanceNameSpaceName": { + input: DataNetwork{ + Spec: DataNetworkSpec{ + NetworkInstance: &corev1.ObjectReference{ + Namespace: "a", + Name: "a", + }, + }, + }, + want: types.NamespacedName{ + Namespace: "a", + Name: "a", + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := tc.input.GetNetworkInstance() + + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("TestGetNetworkInstanc: -want, +got:\n%s", diff) + } + + }) + } +} + +func TestDNNGetPools(t *testing.T) { + tests := map[string]struct { + input DataNetwork + want []*Pool + }{ + "GetPools Empty": { + input: DataNetwork{ + Spec: DataNetworkSpec{}, + }, + want: []*Pool{}, + }, + "GetPools Single": { + input: DataNetwork{ + Spec: DataNetworkSpec{ + Pools: []Pool{ + { + Name: pointer.String("a"), + PrefixLength: 126, + }, + }, + }, + }, + want: []*Pool{ + { + Name: pointer.String("a"), + PrefixLength: 126, + }, + }, + }, + "GetPools Multiple": { + input: DataNetwork{ + Spec: DataNetworkSpec{ + Pools: []Pool{ + { + Name: pointer.String("a"), + PrefixLength: 126, + }, + { + Name: pointer.String("b"), + PrefixLength: 16, + }, + }, + }, + }, + want: []*Pool{ + { + Name: pointer.String("a"), + PrefixLength: 126, + }, + { + Name: pointer.String("b"), + PrefixLength: 16, + }, + }, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := tc.input.GetPools() + + if len(got) != len(tc.want) { + t.Errorf("TestDNNGetPools: unexpected length -want %d, +got: %d\n", len(tc.want), len(got)) + } else { + for i, gotPool := range got { + if diff := cmp.Diff(tc.want[i].GetName(), gotPool.GetName()); diff != "" { + t.Errorf("TestDNNGetPools name: -want, +got:\n%s", diff) + } + if diff := cmp.Diff(tc.want[i].GetPrefixLength(), gotPool.GetPrefixLength()); diff != "" { + t.Errorf("TestDNNGetPools prefixlength: -want, +got:\n%s", diff) + } + } + } + }) + } +} diff --git a/nf_requirements/v1alpha1/dnn_types.go b/nf_requirements/v1alpha1/dnn_types.go index 0a2c2041..8406d108 100644 --- a/nf_requirements/v1alpha1/dnn_types.go +++ b/nf_requirements/v1alpha1/dnn_types.go @@ -36,10 +36,10 @@ type DataNetwork struct { type DataNetworkSpec struct { // Pools defines the parameters of the IP pool associated with the DNN - Pools []*Pool `json:"pools,omitempty"` + Pools []Pool `json:"pools,omitempty"` // NetworkInstance defines the networkInstance context to which this DNN belongs // Name and optionally Namespace is used here - NetworkInstance corev1.ObjectReference `json:"networkInstance" yaml:"networkInstance"` + NetworkInstance *corev1.ObjectReference `json:"networkInstance" yaml:"networkInstance"` } type Pool struct { @@ -47,13 +47,14 @@ type Pool struct { // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 - Name string `json:"name,omitempty" yaml:"name,omitempty"` + // +kubebuilder:validation:Optional + Name *string `json:"name,omitempty" yaml:"name,omitempty"` // PrefixLength define the size of the pool PrefixLength uint8 `json:"prefixLength,omitempty" yaml:"prefixLength,omitempty"` } type DataNetworkStatus struct { - IPAllocationStatus *ipamv1alpha1.IPAllocationStatus `json:"ipAllocationStatus,omitempty" yaml:"ipAllocationStatus,omitempty"` + IPAllocationStatus []ipamv1alpha1.IPAllocationStatus `json:"ipAllocationStatus,omitempty" yaml:"ipAllocationStatus,omitempty"` } // DataNetworkName type metadata. diff --git a/nf_requirements/v1alpha1/interface_interfaces.go b/nf_requirements/v1alpha1/interface_interfaces.go index 1042586e..80126289 100644 --- a/nf_requirements/v1alpha1/interface_interfaces.go +++ b/nf_requirements/v1alpha1/interface_interfaces.go @@ -16,13 +16,8 @@ limitations under the License. package v1alpha1 -import "fmt" - -const ( - errMissingNetworkInstance = "missing networkInstance" - errMissingNetworkInstanceName = "missing networkInstance name" - errUnsupportedAttachmentType = "unsupported attachmentType" - errUnsupportedCNIType = "unsupported cniType" +import ( + "k8s.io/apimachinery/pkg/types" ) type AttachmentType string @@ -44,46 +39,22 @@ const CNITypeIPVLAN CNIType = "ipvlan" // CNITypeMACVLAN defines the macvlan cni const CNITypeMACVLAN CNIType = "macvlan" -func IsCNITypeSupported(s string) bool { - switch s { - case string(CNITypeIPVLAN): - case string(CNITypeMACVLAN): - case string(CNITypeSRIOV): - default: - return false +// GetNetworkInstance returns the networkinstance the interface belongs to +func (r *Interface) GetNetworkInstance() types.NamespacedName { + nsn := types.NamespacedName{} + if r.Spec.NetworkInstance != nil { + nsn.Name = r.Spec.NetworkInstance.Name + nsn.Namespace = r.Spec.NetworkInstance.Namespace } - return true + return nsn } -func IsAttachmentTypeSupported(s string) bool { - switch s { - case string(AttachmentTypeNone): - case string(AttachmentTypeVLAN): - default: - return false - } - return true +// GetCNIType returns the cnitype of the interface +func (r *Interface) GetCNIType() *CNIType { + return r.Spec.CNIType } -func ValidateInterfaceSpec(spec *InterfaceSpec) error { - if spec == nil { - return fmt.Errorf("spec invalid: %s", errMissingNetworkInstance) - } - if spec.AttachmentType != "" { - if !IsAttachmentTypeSupported(string(spec.AttachmentType)) { - return fmt.Errorf("spec invalid: %s, got: %s", errUnsupportedAttachmentType, string(spec.AttachmentType)) - } - } - if spec.CNIType != "" { - if !IsCNITypeSupported(string(spec.CNIType)) { - return fmt.Errorf("spec invalid: %s, got: %s", errUnsupportedCNIType, string(spec.CNIType)) - } - } - if spec.NetworkInstance == nil { - return fmt.Errorf("spec invalid %s", errMissingNetworkInstance) - } - if spec.NetworkInstance.Name == "" { - return fmt.Errorf("spec invalid: %s, got: %s", errMissingNetworkInstanceName, spec.NetworkInstance.Name) - } - return nil +// GetAttachmentType returns the attachment type of the interface +func (r *Interface) GetAttachmentType() *AttachmentType { + return r.Spec.AttachmentType } diff --git a/nf_requirements/v1alpha1/interface_test.go b/nf_requirements/v1alpha1/interface_test.go index 637e5da9..14ec2508 100644 --- a/nf_requirements/v1alpha1/interface_test.go +++ b/nf_requirements/v1alpha1/interface_test.go @@ -17,148 +17,137 @@ limitations under the License. package v1alpha1 import ( - "strings" "testing" "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" ) -func TestIsCNISupported(t *testing.T) { - cases := map[string]struct { - input string - supported bool +func TestInterfaceGetNetworkInstance(t *testing.T) { + tests := map[string]struct { + input Interface + want types.NamespacedName }{ - "TestIsCNISupportedSRIOV": { - input: "sriov", - supported: true, + "GetNetworkInstanceEmpty": { + input: Interface{ + Spec: InterfaceSpec{}, + }, + want: types.NamespacedName{}, }, - "TestIsCNISupportedIPVLAN": { - input: "ipvlan", - supported: true, + "GetNetworkInstanceName": { + input: Interface{ + Spec: InterfaceSpec{ + NetworkInstance: &corev1.ObjectReference{ + Name: "a", + }, + }, + }, + want: types.NamespacedName{ + Name: "a", + }, }, - "TestIsCNISupportedMACVLAN": { - input: "macvlan", - supported: true, + "GetNetworkInstanceNameSpace": { + input: Interface{ + Spec: InterfaceSpec{ + NetworkInstance: &corev1.ObjectReference{ + Namespace: "a", + }, + }, + }, + want: types.NamespacedName{ + Namespace: "a", + }, }, - "TestIsCNISupportedNOK": { - input: "a", - supported: false, + "GetNetworkInstanceNameSpaceName": { + input: Interface{ + Spec: InterfaceSpec{ + NetworkInstance: &corev1.ObjectReference{ + Namespace: "a", + Name: "a", + }, + }, + }, + want: types.NamespacedName{ + Namespace: "a", + Name: "a", + }, }, } - for name, tc := range cases { + for name, tc := range tests { t.Run(name, func(t *testing.T) { - b := IsCNITypeSupported(tc.input) + got := tc.input.GetNetworkInstance() - if diff := cmp.Diff(tc.supported, b); diff != "" { - t.Errorf("TestIsCNISupported: -want, +got:\n%s", diff) + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("TestGetNetworkInstanc: -want, +got:\n%s", diff) } + }) } } -func TestIsAttachmentTypeSupported(t *testing.T) { - cases := map[string]struct { - input string - supported bool +func TestInterfaceGetCNIType(t *testing.T) { + cniType := CNITypeIPVLAN + + tests := map[string]struct { + input Interface + want *CNIType }{ - "TestIsAttachmentTypeSupportedNone": { - input: "none", - supported: true, - }, - "TestIsAttachmentTypeSupportedVLAN": { - input: "vlan", - supported: true, + "TestGetCNITypeEmpty": { + input: Interface{ + Spec: InterfaceSpec{}, + }, + want: nil, }, - "TestIsAttachmentTypeSupportedNOK": { - input: "a", - supported: false, + "TestGetCNIType": { + input: Interface{ + Spec: InterfaceSpec{ + CNIType: &cniType, + }, + }, + want: &cniType, }, } - for name, tc := range cases { + for name, tc := range tests { t.Run(name, func(t *testing.T) { - b := IsAttachmentTypeSupported(tc.input) - - if diff := cmp.Diff(tc.supported, b); diff != "" { - t.Errorf("TestIsCNISupported: -want, +got:\n%s", diff) + got := tc.input.GetCNIType() + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("TestGetCNIType: -want, +got:\n%s", diff) } }) } } -func TestValidateInterfaceSpec(t *testing.T) { - cases := map[string]struct { - input *InterfaceSpec - errExpected bool - err string +func TestInterfaceGetAttachmentType(t *testing.T) { + at := AttachmentTypeVLAN + + tests := map[string]struct { + input Interface + want *AttachmentType }{ - "TestValidateInterfaceSpecOK": { - input: &InterfaceSpec{ - NetworkInstance: &corev1.ObjectReference{ - Name: "a", - }, - CNIType: "ipvlan", - AttachmentType: "none", - }, - errExpected: false, - }, - "TestValidateInterfaceSpecMissingNetworkInstanceName": { - input: &InterfaceSpec{ - NetworkInstance: &corev1.ObjectReference{}, - }, - errExpected: true, - err: errMissingNetworkInstance, - }, - "TestValidateInterfaceSpecEmpty": { - input: &InterfaceSpec{}, - errExpected: true, - err: errMissingNetworkInstance, - }, - "TestValidateInterfaceSpecNil": { - input: nil, - errExpected: true, - err: errMissingNetworkInstance, - }, - "TestValidateInterfaceSpecUnsupportedCNIType": { - input: &InterfaceSpec{ - NetworkInstance: &corev1.ObjectReference{ - Name: "a", - }, - CNIType: "a", - AttachmentType: "none", + "TestGetAttachmentTypeEmpty": { + input: Interface{ + Spec: InterfaceSpec{}, }, - errExpected: true, - err: errUnsupportedCNIType, + want: nil, }, - "TestValidateInterfaceSpecUnsupportedAttachmentType": { - input: &InterfaceSpec{ - NetworkInstance: &corev1.ObjectReference{ - Name: "a", + "TestGetAttachmentType": { + input: Interface{ + Spec: InterfaceSpec{ + AttachmentType: &at, }, - CNIType: "sriov", - AttachmentType: "b", }, - errExpected: true, - err: errUnsupportedAttachmentType, + want: &at, }, } - for name, tc := range cases { + for name, tc := range tests { t.Run(name, func(t *testing.T) { - err := ValidateInterfaceSpec(tc.input) - - if tc.errExpected { - assert.Error(t, err) - if err != nil { - if !strings.Contains(err.Error(), tc.err) { - t.Errorf("err want: %s, got: %s", tc.err, err.Error()) - } - } - } else { - assert.NoError(t, err) + got := tc.input.GetAttachmentType() + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("TestGetAttachmentType: -want, +got:\n%s", diff) } }) } diff --git a/nf_requirements/v1alpha1/interface_types.go b/nf_requirements/v1alpha1/interface_types.go index 2bb8dd0b..68502356 100644 --- a/nf_requirements/v1alpha1/interface_types.go +++ b/nf_requirements/v1alpha1/interface_types.go @@ -42,10 +42,12 @@ type InterfaceSpec struct { NetworkInstance *corev1.ObjectReference `json:"networkInstance" yaml:"networkInstance"` // CNIType defines the cniType that is used to attach the interface to the pod // +kubebuilder:validation:Enum=sriov;ipvlan;macvlan - CNIType CNIType `json:"cniType,omitempty" yaml:"cniType,omitempty"` + // +kubebuilder:validation:Optional + CNIType *CNIType `json:"cniType,omitempty" yaml:"cniType,omitempty"` // AttachmentType defines if the interface is attached using a vlan or not // +kubebuilder:validation:Enum=none;vlan - AttachmentType AttachmentType `json:"attachmentType,omitempty" yaml:"attachmentType,omitempty"` + // +kubebuilder:validation:Optional + AttachmentType *AttachmentType `json:"attachmentType,omitempty" yaml:"attachmentType,omitempty"` } type InterfaceStatus struct { diff --git a/nf_requirements/v1alpha1/zz_generated.deepcopy.go b/nf_requirements/v1alpha1/zz_generated.deepcopy.go index 9061502f..35e632f6 100644 --- a/nf_requirements/v1alpha1/zz_generated.deepcopy.go +++ b/nf_requirements/v1alpha1/zz_generated.deepcopy.go @@ -2,7 +2,7 @@ // +build !ignore_autogenerated /* -Copyright 2023 Nephio. +Copyright 2023 The Nephio Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -58,8 +58,31 @@ func (in *Capacity) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CapacitySpec) DeepCopyInto(out *CapacitySpec) { *out = *in - out.MaxUplinkThroughput = in.MaxUplinkThroughput.DeepCopy() - out.MaxDownlinkThroughput = in.MaxDownlinkThroughput.DeepCopy() + if in.MaxUplinkThroughput != nil { + in, out := &in.MaxUplinkThroughput, &out.MaxUplinkThroughput + x := (*in).DeepCopy() + *out = &x + } + if in.MaxDownlinkThroughput != nil { + in, out := &in.MaxDownlinkThroughput, &out.MaxDownlinkThroughput + x := (*in).DeepCopy() + *out = &x + } + if in.MaxSessions != nil { + in, out := &in.MaxSessions, &out.MaxSessions + *out = new(int) + **out = **in + } + if in.MaxSubscribers != nil { + in, out := &in.MaxSubscribers, &out.MaxSubscribers + *out = new(int) + **out = **in + } + if in.MaxNFConnections != nil { + in, out := &in.MaxNFConnections, &out.MaxNFConnections + *out = new(uint16) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CapacitySpec. @@ -119,16 +142,16 @@ func (in *DataNetworkSpec) DeepCopyInto(out *DataNetworkSpec) { *out = *in if in.Pools != nil { in, out := &in.Pools, &out.Pools - *out = make([]*Pool, len(*in)) + *out = make([]Pool, len(*in)) for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(Pool) - **out = **in - } + (*in)[i].DeepCopyInto(&(*out)[i]) } } - out.NetworkInstance = in.NetworkInstance + if in.NetworkInstance != nil { + in, out := &in.NetworkInstance, &out.NetworkInstance + *out = new(v1.ObjectReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataNetworkSpec. @@ -146,8 +169,10 @@ func (in *DataNetworkStatus) DeepCopyInto(out *DataNetworkStatus) { *out = *in if in.IPAllocationStatus != nil { in, out := &in.IPAllocationStatus, &out.IPAllocationStatus - *out = new(ipamv1alpha1.IPAllocationStatus) - (*in).DeepCopyInto(*out) + *out = make([]ipamv1alpha1.IPAllocationStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -196,6 +221,16 @@ func (in *InterfaceSpec) DeepCopyInto(out *InterfaceSpec) { *out = new(v1.ObjectReference) **out = **in } + if in.CNIType != nil { + in, out := &in.CNIType, &out.CNIType + *out = new(CNIType) + **out = **in + } + if in.AttachmentType != nil { + in, out := &in.AttachmentType, &out.AttachmentType + *out = new(AttachmentType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InterfaceSpec. @@ -236,6 +271,11 @@ func (in *InterfaceStatus) DeepCopy() *InterfaceStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Pool) DeepCopyInto(out *Pool) { *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Pool.