diff --git a/Dockerfile b/Dockerfile index 65d40e2..7b14280 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the operator binary -FROM golang:1.20.5 as builder +FROM golang:1.21.6 as builder ARG TARGETOS ARG TARGETARCH @@ -20,7 +20,7 @@ COPY controllers/ controllers/ # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o free5gc-operator -C free5gc-operator/ +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -C free5gc-operator/ -a -o free5gc-operator # Use distroless as minimal base image to package the operator binary # Refer to https://github.com/GoogleContainerTools/distroless for more details diff --git a/Makefile b/Makefile index cfd7564..773a79a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -GO_VERSION ?= 1.20.5 +GO_VERSION ?= 1.21.6 GOLANG_CI_VER ?= v1.52 GOSEC_VER ?= 2.15.0 TEST_COVERAGE_FILE=lcov.info @@ -72,7 +72,8 @@ help: ## Display this help. .PHONY: manifests manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - $(CONTROLLER_GEN) rbac:roleName=free5gc-operator-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases + $(CONTROLLER_GEN) rbac:roleName=free5gc-operator-role webhook paths="./..." +# $(CONTROLLER_GEN) rbac:roleName=free5gc-operator-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases .PHONY: generate generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. @@ -156,13 +157,13 @@ docker-push: ## Push docker image with the operator. ##@ Deployment -.PHONY: install -install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. - $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f - +# .PHONY: install +# install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. +# $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f - -.PHONY: uninstall -uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - +# .PHONY: uninstall +# uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. +# $(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - .PHONY: deploy deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. diff --git a/README.md b/README.md index f5ffd80..fece6ac 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,50 @@ free5gc-operator ================ -free5GC operator for Nephio. +A Kubernetes operator for [free5GC](https://free5gc.org/). Description ----------- -The Nephio free5GC operator takes the Nephio community produced XXXDeployment (where XXX = AMF | SMF | UPF) custom resources, and deploys the corresponding free5GC AMF | SMF | UPF onto the cluster based on the CR's specifications. +Manages deployments of free5GC's AMF, SMF, and UPF network functions by reconciling Nephio's +`NFDeployment` custom resources for the `amf.free5gc.io`, `smf.free5gc.io`, and `upf.free5gc.io` +providers. Getting Started --------------- -Prior to running the free5GC operator, Multus needs to be installed on cluster with the macvlan CNI. - ### Deploy the CRDs +We need the Nephio API CRDs from the [api repository](https://github.com/nephio-project/api): + ```sh -make install +TAG=main +kubectl apply -f https://raw.githubusercontent.com/nephio-project/api/$TAG/config/crd/bases/workload.nephio.org_nfdeployments.yaml +kubectl apply -f https://raw.githubusercontent.com/nephio-project/api/$TAG/config/crd/bases/workload.nephio.org_nfconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/nephio-project/api/$TAG/config/crd/bases/ref.nephio.org_configs.yaml ``` +(Replace `TAG` with a specific tagged version, e.g. `v2.0.0`) + ### Run the Operator +Multus needs to be installed on cluster with the "macvlan" CNI plugin. + For testing, you can run the operator locally against the cluster: ```sh make run ``` -### Deploy the Operator - -Use your own Docker Hub registry: +Or you can build an image: ```sh make docker-build docker-push REGISTRY=myregistry ``` -Then deploy to the cluster: +(Use your own Docker Hub registry) + +Then deploy it the cluster: ```sh make deploy REGISTRY=myregistry @@ -47,8 +56,8 @@ make deploy REGISTRY=myregistry kubectl apply -f test/ ``` - -## License +License +------- Copyright 2023 The Nephio Authors. diff --git a/config/crd/bases/workload.nephio.org_amfdeployments.yaml b/config/crd/bases/workload.nephio.org_amfdeployments.yaml deleted file mode 100644 index fc5d62e..0000000 --- a/config/crd/bases/workload.nephio.org_amfdeployments.yaml +++ /dev/null @@ -1,400 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: amfdeployments.workload.nephio.org -spec: - group: workload.nephio.org - names: - kind: AMFDeployment - listKind: AMFDeploymentList - plural: amfdeployments - singular: amfdeployment - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - capacity: - description: capacity defines the capacity characteristics of the - NF deployment - properties: - maxDownlinkThroughput: - anyOf: - - type: integer - - type: string - description: MaxDownlinkThroughput defines the max downlink dataplane - throughput - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - maxNFConnections: - description: MaxNFConnections defines the max NF(s) that can be - connected to this NF/device - type: integer - maxSessions: - description: MaxSessions defines the max sessions of the control - plane expressed in unit of 1000s - type: integer - maxSubscribers: - description: MaxSubscribers defines the max subscribers expressed - in unit of 1000s - type: integer - maxUplinkThroughput: - anyOf: - - type: integer - - type: string - description: MaxUplinkThroughput defines the max uplink dataplane - throughput - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - configRefs: - description: configRef defines addiitonal configuration references - the nf depends upon - items: - description: "ObjectReference contains enough information to let - you inspect or modify the referred object. --- New uses of this - type are discouraged because of difficulty describing its usage - when embedded in APIs. 1. Ignored fields. It includes many fields - which are not generally honored. For instance, ResourceVersion - and FieldPath are both very rarely valid in actual usage. 2. Invalid - usage help. It is impossible to add specific help for individual - usage. In most embedded usages, there are particular restrictions - like, \"must refer only to types A and B\" or \"UID not honored\" - or \"name must be restricted\". Those cannot be well described - when embedded. 3. Inconsistent validation. Because the usages - are different, the validation rules are different by usage, which - makes it hard for users to predict what will happen. 4. The fields - are both imprecise and overly precise. Kind is not a precise - mapping to a URL. This can produce ambiguity during interpretation - and require a REST mapping. In most cases, the dependency is - on the group,resource tuple and the version of the actual struct - is irrelevant. 5. We cannot easily change it. Because this type - is embedded in many locations, updates to this type will affect - numerous schemas. Don't make new APIs embed an underspecified - API type they do not control. \n Instead of using this type, create - a locally provided and used type that is well-focused on your - reference. For example, ServiceReferences for admission registration: - https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 - ." - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: 'If referring to a piece of an object instead of - an entire object, this string should contain a valid JSON/Go - field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part of - an object. TODO: this design is not final and this field is - subject to change in the future.' - type: string - kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' - type: string - resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' - type: string - uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' - type: string - type: object - x-kubernetes-map-type: atomic - type: array - interfaces: - description: Interfaces defines the interfaces associated with the - NF deployment - items: - description: InterfaceConfig defines the configuration of the interface - properties: - ipv4: - description: IPv4 defines the ipv4 configuration of the interface - properties: - address: - description: Address defines the IPv4 address and prefix - length in CIDR notation [IP prefix, range IPv4 with host - bits] - type: string - gateway: - description: Gateway defines the IPv4 address associated - to the interface as a gateway - type: string - required: - - address - type: object - ipv6: - description: IPv6Config defines the ipv6 configuration of the - interface - properties: - address: - description: Address defines the IPv6 address and prefix - length in CIDR notation [IP prefix, range IPv6 with host - bits] - type: string - gateway: - description: Gateway defines the IPv6 address associated - to the interface as a gateway - type: string - required: - - address - type: object - name: - description: Name defines the name of the interface - maxLength: 253 - minLength: 1 - type: string - vlanID: - description: VLANID defines the specific vlan id associated - on this interface - type: integer - required: - - name - type: object - type: array - networkInstances: - description: NetworkInstances defines the network instances associated - with the NF deployment - items: - description: A networkInstance is a Layer 3 forwarding construct - such as a virtual routing and forwarding (VRF) instance, - properties: - bgp: - description: BGP defines the BGP configuration associated with - the network instance - properties: - autonomousSystem: - description: AutonomousSystem defines the AS number of the - bgp process - type: integer - bgpNeighbors: - description: BGPNeigbors defines the configuration of the - BGP neighbor - items: - properties: - address: - description: Address defines the IPv4 or IPv6 address - of the BGP neighbor - type: string - name: - description: BGP interface name, MUST match the one - use in InterfaceConfig - type: string - peerAS: - description: PeerAS defines the AS number of the bgp - peer - type: integer - required: - - address - - peerAS - type: object - type: array - routerID: - description: RouterID defines the router ID of the bgp process - type: string - required: - - autonomousSystem - - bgpNeighbors - - routerID - type: object - dataNetworks: - description: DataNetworks defines the data networks assocated - with the network instance - items: - description: A DataNetwork defines the Data Network name defined - by 3GPP - properties: - name: - description: Name defines the name of the data network - maxLength: 253 - minLength: 1 - type: string - pool: - description: Pool defines the list of address pools associated - with the data network - items: - properties: - prefix: - description: Prefix defines the ip cidr in prefix - notation. It is defines as a subnet - pattern: (([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/(([0-9])|([1-2][0-9])|(3[0-2]))|((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8]))) - type: string - required: - - prefix - type: object - type: array - type: object - type: array - interfaces: - description: interfaces defines the interfaces associated with - the network instance - items: - type: string - type: array - name: - description: Name defines the name of the network instance - maxLength: 253 - minLength: 1 - type: string - peers: - description: Peers defines the peer configuration associated - with the network instance - items: - description: A PeerConfig defines the peer configuration - properties: - ipv4: - description: IPv4 defines the ipv4 configuration of the - peer - properties: - address: - description: Address defines the IPv4 address and - prefix length in CIDR notation [IP prefix, range - IPv4 with host bits] - type: string - gateway: - description: Gateway defines the IPv4 address associated - to the interface as a gateway - type: string - required: - - address - type: object - ipv6: - description: IPv6 defines the ipv6 configuration of the - peer - properties: - address: - description: Address defines the IPv6 address and - prefix length in CIDR notation [IP prefix, range - IPv6 with host bits] - type: string - gateway: - description: Gateway defines the IPv6 address associated - to the interface as a gateway - type: string - required: - - address - type: object - name: - description: Name defines the name of the data network - maxLength: 253 - minLength: 1 - type: string - type: object - type: array - required: - - name - type: object - type: array - type: object - status: - properties: - conditions: - description: Conditions define the current state of the NF deployment - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: The generation observed by the deployment controller. - format: int32 - type: integer - required: - - observedGeneration - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/bases/workload.nephio.org_nfdeployments.yaml b/config/crd/bases/workload.nephio.org_nfdeployments.yaml deleted file mode 100644 index 58880a4..0000000 --- a/config/crd/bases/workload.nephio.org_nfdeployments.yaml +++ /dev/null @@ -1,404 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: nfdeployments.workload.nephio.org -spec: - group: workload.nephio.org - names: - kind: NFDeployment - listKind: NFDeploymentList - plural: nfdeployments - singular: nfdeployment - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - provider: - description: - "Provider defines which provider implement this NFDeployment" - type: string - capacity: - description: capacity defines the capacity characteristics of the - NF deployment - properties: - maxDownlinkThroughput: - anyOf: - - type: integer - - type: string - description: MaxDownlinkThroughput defines the max downlink dataplane - throughput - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - maxNFConnections: - description: MaxNFConnections defines the max NF(s) that can be - connected to this NF/device - type: integer - maxSessions: - description: MaxSessions defines the max sessions of the control - plane expressed in unit of 1000s - type: integer - maxSubscribers: - description: MaxSubscribers defines the max subscribers expressed - in unit of 1000s - type: integer - maxUplinkThroughput: - anyOf: - - type: integer - - type: string - description: MaxUplinkThroughput defines the max uplink dataplane - throughput - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - parametersRefs: - description: configRef defines addiitonal configuration references - the nf depends upon - items: - description: "ObjectReference contains enough information to let - you inspect or modify the referred object. --- New uses of this - type are discouraged because of difficulty describing its usage - when embedded in APIs. 1. Ignored fields. It includes many fields - which are not generally honored. For instance, ResourceVersion - and FieldPath are both very rarely valid in actual usage. 2. Invalid - usage help. It is impossible to add specific help for individual - usage. In most embedded usages, there are particular restrictions - like, \"must refer only to types A and B\" or \"UID not honored\" - or \"name must be restricted\". Those cannot be well described - when embedded. 3. Inconsistent validation. Because the usages - are different, the validation rules are different by usage, which - makes it hard for users to predict what will happen. 4. The fields - are both imprecise and overly precise. Kind is not a precise - mapping to a URL. This can produce ambiguity during interpretation - and require a REST mapping. In most cases, the dependency is - on the group,resource tuple and the version of the actual struct - is irrelevant. 5. We cannot easily change it. Because this type - is embedded in many locations, updates to this type will affect - numerous schemas. Don't make new APIs embed an underspecified - API type they do not control. \n Instead of using this type, create - a locally provided and used type that is well-focused on your - reference. For example, ServiceReferences for admission registration: - https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 - ." - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: 'If referring to a piece of an object instead of - an entire object, this string should contain a valid JSON/Go - field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part of - an object. TODO: this design is not final and this field is - subject to change in the future.' - type: string - kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' - type: string - resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' - type: string - uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' - type: string - type: object - x-kubernetes-map-type: atomic - type: array - interfaces: - description: Interfaces defines the interfaces associated with the - NF deployment - items: - description: InterfaceConfig defines the configuration of the interface - properties: - ipv4: - description: IPv4 defines the ipv4 configuration of the interface - properties: - address: - description: Address defines the IPv4 address and prefix - length in CIDR notation [IP prefix, range IPv4 with host - bits] - type: string - gateway: - description: Gateway defines the IPv4 address associated - to the interface as a gateway - type: string - required: - - address - type: object - ipv6: - description: IPv6Config defines the ipv6 configuration of the - interface - properties: - address: - description: Address defines the IPv6 address and prefix - length in CIDR notation [IP prefix, range IPv6 with host - bits] - type: string - gateway: - description: Gateway defines the IPv6 address associated - to the interface as a gateway - type: string - required: - - address - type: object - name: - description: Name defines the name of the interface - maxLength: 253 - minLength: 1 - type: string - vlanID: - description: VLANID defines the specific vlan id associated - on this interface - type: integer - required: - - name - type: object - type: array - networkInstances: - description: NetworkInstances defines the network instances associated - with the NF deployment - items: - description: A networkInstance is a Layer 3 forwarding construct - such as a virtual routing and forwarding (VRF) instance, - properties: - bgp: - description: BGP defines the BGP configuration associated with - the network instance - properties: - autonomousSystem: - description: AutonomousSystem defines the AS number of the - bgp process - type: integer - bgpNeighbors: - description: BGPNeigbors defines the configuration of the - BGP neighbor - items: - properties: - address: - description: Address defines the IPv4 or IPv6 address - of the BGP neighbor - type: string - name: - description: BGP interface name, MUST match the one - use in InterfaceConfig - type: string - peerAS: - description: PeerAS defines the AS number of the bgp - peer - type: integer - required: - - address - - peerAS - type: object - type: array - routerID: - description: RouterID defines the router ID of the bgp process - type: string - required: - - autonomousSystem - - bgpNeighbors - - routerID - type: object - dataNetworks: - description: DataNetworks defines the data networks assocated - with the network instance - items: - description: A DataNetwork defines the Data Network name defined - by 3GPP - properties: - name: - description: Name defines the name of the data network - maxLength: 253 - minLength: 1 - type: string - pool: - description: Pool defines the list of address pools associated - with the data network - items: - properties: - prefix: - description: Prefix defines the ip cidr in prefix - notation. It is defines as a subnet - pattern: (([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/(([0-9])|([1-2][0-9])|(3[0-2]))|((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8]))) - type: string - required: - - prefix - type: object - type: array - type: object - type: array - interfaces: - description: interfaces defines the interfaces associated with - the network instance - items: - type: string - type: array - name: - description: Name defines the name of the network instance - maxLength: 253 - minLength: 1 - type: string - peers: - description: Peers defines the peer configuration associated - with the network instance - items: - description: A PeerConfig defines the peer configuration - properties: - ipv4: - description: IPv4 defines the ipv4 configuration of the - peer - properties: - address: - description: Address defines the IPv4 address and - prefix length in CIDR notation [IP prefix, range - IPv4 with host bits] - type: string - gateway: - description: Gateway defines the IPv4 address associated - to the interface as a gateway - type: string - required: - - address - type: object - ipv6: - description: IPv6 defines the ipv6 configuration of the - peer - properties: - address: - description: Address defines the IPv6 address and - prefix length in CIDR notation [IP prefix, range - IPv6 with host bits] - type: string - gateway: - description: Gateway defines the IPv6 address associated - to the interface as a gateway - type: string - required: - - address - type: object - name: - description: Name defines the name of the data network - maxLength: 253 - minLength: 1 - type: string - type: object - type: array - required: - - name - type: object - type: array - type: object - status: - properties: - conditions: - description: Conditions define the current state of the NF deployment - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: The generation observed by the deployment controller. - format: int32 - type: integer - required: - - observedGeneration - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/bases/workload.nephio.org_smfdeployments.yaml b/config/crd/bases/workload.nephio.org_smfdeployments.yaml deleted file mode 100644 index 50c7627..0000000 --- a/config/crd/bases/workload.nephio.org_smfdeployments.yaml +++ /dev/null @@ -1,400 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: smfdeployments.workload.nephio.org -spec: - group: workload.nephio.org - names: - kind: SMFDeployment - listKind: SMFDeploymentList - plural: smfdeployments - singular: smfdeployment - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - capacity: - description: capacity defines the capacity characteristics of the - NF deployment - properties: - maxDownlinkThroughput: - anyOf: - - type: integer - - type: string - description: MaxDownlinkThroughput defines the max downlink dataplane - throughput - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - maxNFConnections: - description: MaxNFConnections defines the max NF(s) that can be - connected to this NF/device - type: integer - maxSessions: - description: MaxSessions defines the max sessions of the control - plane expressed in unit of 1000s - type: integer - maxSubscribers: - description: MaxSubscribers defines the max subscribers expressed - in unit of 1000s - type: integer - maxUplinkThroughput: - anyOf: - - type: integer - - type: string - description: MaxUplinkThroughput defines the max uplink dataplane - throughput - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - configRefs: - description: configRef defines addiitonal configuration references - the nf depends upon - items: - description: "ObjectReference contains enough information to let - you inspect or modify the referred object. --- New uses of this - type are discouraged because of difficulty describing its usage - when embedded in APIs. 1. Ignored fields. It includes many fields - which are not generally honored. For instance, ResourceVersion - and FieldPath are both very rarely valid in actual usage. 2. Invalid - usage help. It is impossible to add specific help for individual - usage. In most embedded usages, there are particular restrictions - like, \"must refer only to types A and B\" or \"UID not honored\" - or \"name must be restricted\". Those cannot be well described - when embedded. 3. Inconsistent validation. Because the usages - are different, the validation rules are different by usage, which - makes it hard for users to predict what will happen. 4. The fields - are both imprecise and overly precise. Kind is not a precise - mapping to a URL. This can produce ambiguity during interpretation - and require a REST mapping. In most cases, the dependency is - on the group,resource tuple and the version of the actual struct - is irrelevant. 5. We cannot easily change it. Because this type - is embedded in many locations, updates to this type will affect - numerous schemas. Don't make new APIs embed an underspecified - API type they do not control. \n Instead of using this type, create - a locally provided and used type that is well-focused on your - reference. For example, ServiceReferences for admission registration: - https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 - ." - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: 'If referring to a piece of an object instead of - an entire object, this string should contain a valid JSON/Go - field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part of - an object. TODO: this design is not final and this field is - subject to change in the future.' - type: string - kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' - type: string - resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' - type: string - uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' - type: string - type: object - x-kubernetes-map-type: atomic - type: array - interfaces: - description: Interfaces defines the interfaces associated with the - NF deployment - items: - description: InterfaceConfig defines the configuration of the interface - properties: - ipv4: - description: IPv4 defines the ipv4 configuration of the interface - properties: - address: - description: Address defines the IPv4 address and prefix - length in CIDR notation [IP prefix, range IPv4 with host - bits] - type: string - gateway: - description: Gateway defines the IPv4 address associated - to the interface as a gateway - type: string - required: - - address - type: object - ipv6: - description: IPv6Config defines the ipv6 configuration of the - interface - properties: - address: - description: Address defines the IPv6 address and prefix - length in CIDR notation [IP prefix, range IPv6 with host - bits] - type: string - gateway: - description: Gateway defines the IPv6 address associated - to the interface as a gateway - type: string - required: - - address - type: object - name: - description: Name defines the name of the interface - maxLength: 253 - minLength: 1 - type: string - vlanID: - description: VLANID defines the specific vlan id associated - on this interface - type: integer - required: - - name - type: object - type: array - networkInstances: - description: NetworkInstances defines the network instances associated - with the NF deployment - items: - description: A networkInstance is a Layer 3 forwarding construct - such as a virtual routing and forwarding (VRF) instance, - properties: - bgp: - description: BGP defines the BGP configuration associated with - the network instance - properties: - autonomousSystem: - description: AutonomousSystem defines the AS number of the - bgp process - type: integer - bgpNeighbors: - description: BGPNeigbors defines the configuration of the - BGP neighbor - items: - properties: - address: - description: Address defines the IPv4 or IPv6 address - of the BGP neighbor - type: string - name: - description: BGP interface name, MUST match the one - use in InterfaceConfig - type: string - peerAS: - description: PeerAS defines the AS number of the bgp - peer - type: integer - required: - - address - - peerAS - type: object - type: array - routerID: - description: RouterID defines the router ID of the bgp process - type: string - required: - - autonomousSystem - - bgpNeighbors - - routerID - type: object - dataNetworks: - description: DataNetworks defines the data networks assocated - with the network instance - items: - description: A DataNetwork defines the Data Network name defined - by 3GPP - properties: - name: - description: Name defines the name of the data network - maxLength: 253 - minLength: 1 - type: string - pool: - description: Pool defines the list of address pools associated - with the data network - items: - properties: - prefix: - description: Prefix defines the ip cidr in prefix - notation. It is defines as a subnet - pattern: (([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/(([0-9])|([1-2][0-9])|(3[0-2]))|((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8]))) - type: string - required: - - prefix - type: object - type: array - type: object - type: array - interfaces: - description: interfaces defines the interfaces associated with - the network instance - items: - type: string - type: array - name: - description: Name defines the name of the network instance - maxLength: 253 - minLength: 1 - type: string - peers: - description: Peers defines the peer configuration associated - with the network instance - items: - description: A PeerConfig defines the peer configuration - properties: - ipv4: - description: IPv4 defines the ipv4 configuration of the - peer - properties: - address: - description: Address defines the IPv4 address and - prefix length in CIDR notation [IP prefix, range - IPv4 with host bits] - type: string - gateway: - description: Gateway defines the IPv4 address associated - to the interface as a gateway - type: string - required: - - address - type: object - ipv6: - description: IPv6 defines the ipv6 configuration of the - peer - properties: - address: - description: Address defines the IPv6 address and - prefix length in CIDR notation [IP prefix, range - IPv6 with host bits] - type: string - gateway: - description: Gateway defines the IPv6 address associated - to the interface as a gateway - type: string - required: - - address - type: object - name: - description: Name defines the name of the data network - maxLength: 253 - minLength: 1 - type: string - type: object - type: array - required: - - name - type: object - type: array - type: object - status: - properties: - conditions: - description: Conditions define the current state of the NF deployment - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: The generation observed by the deployment controller. - format: int32 - type: integer - required: - - observedGeneration - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/bases/workload.nephio.org_upfdeployments.yaml b/config/crd/bases/workload.nephio.org_upfdeployments.yaml deleted file mode 100644 index 9fa4a47..0000000 --- a/config/crd/bases/workload.nephio.org_upfdeployments.yaml +++ /dev/null @@ -1,445 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.11.4 - creationTimestamp: null - name: upfdeployments.workload.nephio.org -spec: - group: workload.nephio.org - names: - kind: UPFDeployment - listKind: UPFDeploymentList - plural: upfdeployments - singular: upfdeployment - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: - "APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources" - type: string - kind: - description: - "Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" - type: string - metadata: - type: object - spec: - properties: - capacity: - description: - capacity defines the capacity characteristics of the - NF deployment - properties: - maxDownlinkThroughput: - anyOf: - - type: integer - - type: string - description: - MaxDownlinkThroughput defines the max downlink dataplane - throughput - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - maxNFConnections: - description: - MaxNFConnections defines the max NF(s) that can be - connected to this NF/device - type: integer - maxSessions: - description: - MaxSessions defines the max sessions of the control - plane expressed in unit of 1000s - type: integer - maxSubscribers: - description: - MaxSubscribers defines the max subscribers expressed - in unit of 1000s - type: integer - maxUplinkThroughput: - anyOf: - - type: integer - - type: string - description: - MaxUplinkThroughput defines the max uplink dataplane - throughput - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - configRefs: - description: - configRef defines addiitonal configuration references - the nf depends upon - items: - description: - "ObjectReference contains enough information to let - you inspect or modify the referred object. --- New uses of this - type are discouraged because of difficulty describing its usage - when embedded in APIs. 1. Ignored fields. It includes many fields - which are not generally honored. For instance, ResourceVersion - and FieldPath are both very rarely valid in actual usage. 2. Invalid - usage help. It is impossible to add specific help for individual - usage. In most embedded usages, there are particular restrictions - like, \"must refer only to types A and B\" or \"UID not honored\" - or \"name must be restricted\". Those cannot be well described - when embedded. 3. Inconsistent validation. Because the usages - are different, the validation rules are different by usage, which - makes it hard for users to predict what will happen. 4. The fields - are both imprecise and overly precise. Kind is not a precise - mapping to a URL. This can produce ambiguity during interpretation - and require a REST mapping. In most cases, the dependency is - on the group,resource tuple and the version of the actual struct - is irrelevant. 5. We cannot easily change it. Because this type - is embedded in many locations, updates to this type will affect - numerous schemas. Don't make new APIs embed an underspecified - API type they do not control. \n Instead of using this type, create - a locally provided and used type that is well-focused on your - reference. For example, ServiceReferences for admission registration: - https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 - ." - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: - 'If referring to a piece of an object instead of - an entire object, this string should contain a valid JSON/Go - field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part of - an object. TODO: this design is not final and this field is - subject to change in the future.' - type: string - kind: - description: "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" - type: string - name: - description: "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" - type: string - namespace: - description: "Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/" - type: string - resourceVersion: - description: - "Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency" - type: string - uid: - description: "UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids" - type: string - type: object - x-kubernetes-map-type: atomic - type: array - interfaces: - description: - Interfaces defines the interfaces associated with the - NF deployment - items: - description: InterfaceConfig defines the configuration of the interface - properties: - ipv4: - description: IPv4 defines the ipv4 configuration of the interface - properties: - address: - description: - Address defines the IPv4 address and prefix - length in CIDR notation [IP prefix, range IPv4 with host - bits] - type: string - gateway: - description: - Gateway defines the IPv4 address associated - to the interface as a gateway - type: string - required: - - address - type: object - ipv6: - description: - IPv6Config defines the ipv6 configuration of the - interface - properties: - address: - description: - Address defines the IPv6 address and prefix - length in CIDR notation [IP prefix, range IPv6 with host - bits] - type: string - gateway: - description: - Gateway defines the IPv6 address associated - to the interface as a gateway - type: string - required: - - address - type: object - name: - description: Name defines the name of the interface - maxLength: 253 - minLength: 1 - type: string - vlanID: - description: - VLANID defines the specific vlan id associated - on this interface - type: integer - required: - - name - type: object - type: array - networkInstances: - description: - NetworkInstances defines the network instances associated - with the NF deployment - items: - description: - A networkInstance is a Layer 3 forwarding construct - such as a virtual routing and forwarding (VRF) instance, - properties: - bgp: - description: - BGP defines the BGP configuration associated with - the network instance - properties: - autonomousSystem: - description: - AutonomousSystem defines the AS number of the - bgp process - type: integer - bgpNeighbors: - description: - BGPNeigbors defines the configuration of the - BGP neighbor - items: - properties: - address: - description: - Address defines the IPv4 or IPv6 address - of the BGP neighbor - type: string - name: - description: - BGP interface name, MUST match the one - use in InterfaceConfig - type: string - peerAS: - description: - PeerAS defines the AS number of the bgp - peer - type: integer - required: - - address - - peerAS - type: object - type: array - routerID: - description: RouterID defines the router ID of the bgp process - type: string - required: - - autonomousSystem - - bgpNeighbors - - routerID - type: object - dataNetworks: - description: - DataNetworks defines the data networks assocated - with the network instance - items: - description: - A DataNetwork defines the Data Network name defined - by 3GPP - properties: - name: - description: Name defines the name of the data network - maxLength: 253 - minLength: 1 - type: string - pool: - description: - Pool defines the list of address pools associated - with the data network - items: - properties: - prefix: - description: - Prefix defines the ip cidr in prefix - notation. It is defines as a subnet - pattern: (([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/(([0-9])|([1-2][0-9])|(3[0-2]))|((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8]))) - type: string - required: - - prefix - type: object - type: array - type: object - type: array - interfaces: - description: - interfaces defines the interfaces associated with - the network instance - items: - type: string - type: array - name: - description: Name defines the name of the network instance - maxLength: 253 - minLength: 1 - type: string - peers: - description: - Peers defines the peer configuration associated - with the network instance - items: - description: A PeerConfig defines the peer configuration - properties: - ipv4: - description: - IPv4 defines the ipv4 configuration of the - peer - properties: - address: - description: - Address defines the IPv4 address and - prefix length in CIDR notation [IP prefix, range - IPv4 with host bits] - type: string - gateway: - description: - Gateway defines the IPv4 address associated - to the interface as a gateway - type: string - required: - - address - type: object - ipv6: - description: - IPv6 defines the ipv6 configuration of the - peer - properties: - address: - description: - Address defines the IPv6 address and - prefix length in CIDR notation [IP prefix, range - IPv6 with host bits] - type: string - gateway: - description: - Gateway defines the IPv6 address associated - to the interface as a gateway - type: string - required: - - address - type: object - name: - description: Name defines the name of the data network - maxLength: 253 - minLength: 1 - type: string - type: object - type: array - required: - - name - type: object - type: array - type: object - status: - properties: - conditions: - description: Conditions define the current state of the NF deployment - items: - description: - "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: - lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: - message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: - observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: - reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: - type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - description: The generation observed by the deployment controller. - format: int32 - type: integer - required: - - observedGeneration - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml deleted file mode 100644 index f9b4c6d..0000000 --- a/config/crd/kustomization.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# This kustomization.yaml is not intended to be run by itself, -# since it depends on service name and namespace that are out of this kustomize package. -# It should be run by config/default -resources: - - bases/workload.nephio.org_nfdeployments.yaml -#+kubebuilder:scaffold:crdkustomizeresource - -patchesStrategicMerge: -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. -# patches here are for enabling the conversion webhook for each CRD -#- patches/webhook_in_upfdeployments.yaml -#- patches/webhook_in_smfdeployments.yaml -#+kubebuilder:scaffold:crdkustomizewebhookpatch - -# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. -# patches here are for enabling the CA injection for each CRD -#- patches/cainjection_in_upfdeployments.yaml -#- patches/cainjection_in_smfdeployments.yaml -#+kubebuilder:scaffold:crdkustomizecainjectionpatch - -# the following config is for teaching kustomize how to do kustomization for CRDs. -configurations: - - kustomizeconfig.yaml diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml deleted file mode 100644 index ec5c150..0000000 --- a/config/crd/kustomizeconfig.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# This file is for teaching kustomize how to substitute name and namespace reference in CRD -nameReference: -- kind: Service - version: v1 - fieldSpecs: - - kind: CustomResourceDefinition - version: v1 - group: apiextensions.k8s.io - path: spec/conversion/webhook/clientConfig/service/name - -namespace: -- kind: CustomResourceDefinition - version: v1 - group: apiextensions.k8s.io - path: spec/conversion/webhook/clientConfig/service/namespace - create: false - -varReference: -- path: metadata/annotations diff --git a/config/crd/patches/cainjection_in_upfdeployments.yaml b/config/crd/patches/cainjection_in_upfdeployments.yaml deleted file mode 100644 index 61ec8bd..0000000 --- a/config/crd/patches/cainjection_in_upfdeployments.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition - -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: upfdeployments.workload.nephio.org diff --git a/config/crd/patches/webhook_in_upfdeployments.yaml b/config/crd/patches/webhook_in_upfdeployments.yaml deleted file mode 100644 index 9755cbc..0000000 --- a/config/crd/patches/webhook_in_upfdeployments.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition - -metadata: - name: upfdeployments.workload.nephio.org - -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: free5gc - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 40fc2d0..dbd0ce1 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -13,7 +13,6 @@ namespace: free5gc # someName: someValue bases: -- ../crd - ../rbac - ../operator # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in diff --git a/config/operator/kustomization.yaml b/config/operator/kustomization.yaml index 46e45a3..5ed5c37 100644 --- a/config/operator/kustomization.yaml +++ b/config/operator/kustomization.yaml @@ -4,5 +4,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: operator - newName: docker.io/nephio/free5gc-operator + newName: docker.io/tliron/free5gc-operator newTag: latest diff --git a/config/rbac/.gitignore b/config/rbac/.gitignore new file mode 100644 index 0000000..5359192 --- /dev/null +++ b/config/rbac/.gitignore @@ -0,0 +1 @@ +role.yaml diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml deleted file mode 100644 index 91ae0cb..0000000 --- a/config/rbac/role.yaml +++ /dev/null @@ -1,80 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: free5gc-operator-role -rules: -- apiGroups: - - "" - resources: - - configmaps - - services - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch -- apiGroups: - - "" - resources: - - pods - verbs: - - get - - list - - watch -- apiGroups: - - apps - resources: - - deployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resources: - - deployments/status - verbs: - - get -- apiGroups: - - k8s.cni.cncf.io - resources: - - network-attachment-definitions - verbs: - - get - - list - - watch -- apiGroups: - - workload.nephio.org - resources: - - nfdeployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - workload.nephio.org - resources: - - nfdeployments/status - verbs: - - get - - patch - - update diff --git a/controllers/nf/amf/reconciler.go b/controllers/nf/amf/reconciler.go index 7b92951..1628663 100644 --- a/controllers/nf/amf/reconciler.go +++ b/controllers/nf/amf/reconciler.go @@ -34,7 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -// Reconciles a AMFDeployment resource +// Reconciles a AMF NFDeployment resource type AMFDeploymentReconciler struct { client.Client Scheme *runtime.Scheme @@ -43,23 +43,23 @@ type AMFDeploymentReconciler struct { // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. // TODO(user): Modify the Reconcile function to compare the state specified by -// the AMFDeployment object against the actual cluster state, and then +// the AMF NFDeployment object against the actual cluster state, and then // perform operations to make the cluster state reflect the state specified by // the user. // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile func (r *AMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx).WithValues("AMFDeployment", req.NamespacedName) + log := log.FromContext(ctx).WithValues("NFDeployment", req.NamespacedName, "NF", "AMF") amfDeployment := new(nephiov1alpha1.NFDeployment) err := r.Client.Get(ctx, req.NamespacedName, amfDeployment) if err != nil { if k8serrors.IsNotFound(err) { - log.Info("AMFDeployment resource not found, ignoring sibecausence object must be deleted") + log.Info("AMF NFDeployment resource not found, ignoring sibecausence object must be deleted") return reconcile.Result{}, nil } - log.Error(err, "Failed to get AMFDeployment") + log.Error(err, "Failed to get AMF NFDeployment") return reconcile.Result{}, err } @@ -91,7 +91,7 @@ func (r *AMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques if deploymentFound { deployment := currentDeployment.DeepCopy() - // Updating AMFDeployment status. On the first sets the first Condition to Reconciling. + // Updating AMF NFDeployment status. On the first sets the first Condition to Reconciling. // On the subsequent runs it gets undelying depoyment Conditions and use the last one to decide if status has to be updated. if deployment.DeletionTimestamp == nil { if err := r.syncStatus(ctx, deployment, amfDeployment); err != nil { @@ -117,7 +117,7 @@ func (r *AMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques if !configMapFound { log.Info("Creating ConfigMap", "ConfigMap.namespace", configMap.Namespace, "ConfigMap.name", configMap.Name) - // Set the controller reference, specifying that AMFDeployment controling underlying deployment + // Set the controller reference, specifying that AMF NFDeployment controling underlying deployment if err := ctrl.SetControllerReference(amfDeployment, configMap, r.Scheme); err != nil { log.Error(err, "Got error while setting Owner reference on configmap.", "ConfigMap.namespace", configMap.Namespace, "ConfigMap.name", configMap.Name) } @@ -137,9 +137,9 @@ func (r *AMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques if !serviceFound { service := createService(amfDeployment) - log.Info("Creating AMFDeployment service", "Service.namespace", service.Namespace, "Service.name", service.Name) + log.Info("Creating AMF NFDeployment service", "Service.namespace", service.Namespace, "Service.name", service.Name) - // Set the controller reference, specifying that AMFDeployment controling underlying deployment + // Set the controller reference, specifying that AMF NFDeployment controling underlying deployment if err := ctrl.SetControllerReference(amfDeployment, service, r.Scheme); err != nil { log.Error(err, "Got error while setting Owner reference on AMF service", "Service.namespace", service.Namespace, "Service.name", service.Name) } @@ -154,7 +154,7 @@ func (r *AMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques if !deploymentFound { // Only create Deployment in case all required NADs are present. Otherwise Requeue in 10 sec. if ok := controllers.ValidateNetworkAttachmentDefinitions(ctx, r.Client, log, amfDeployment.Kind, deployment); ok { - // Set the controller reference, specifying that AMFDeployment controls the underlying Deployment + // Set the controller reference, specifying that AMF NFDeployment controls the underlying Deployment if err := ctrl.SetControllerReference(amfDeployment, deployment, r.Scheme); err != nil { log.Error(err, "Got error while setting Owner reference on deployment", "Deployment.namespace", deployment.Namespace, "Deployment.name", deployment.Name) } @@ -172,7 +172,7 @@ func (r *AMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques } } } else { - log.Error(err, fmt.Sprintf("Failed to create Deployment %s\n", err.Error())) + log.Error(err, fmt.Sprintf("Failed to create Deployment %s", err.Error())) return reconcile.Result{}, err } diff --git a/controllers/nf/amf/resources.go b/controllers/nf/amf/resources.go index 6a84f60..d9c957c 100644 --- a/controllers/nf/amf/resources.go +++ b/controllers/nf/amf/resources.go @@ -27,17 +27,17 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" ) -func createDeployment(log logr.Logger, configMapVersion string, nfDeployment *nephiov1alpha1.NFDeployment) (*appsv1.Deployment, error) { - namespace := nfDeployment.Namespace - instanceName := nfDeployment.Name - spec := nfDeployment.Spec +func createDeployment(log logr.Logger, configMapVersion string, amfDeployment *nephiov1alpha1.NFDeployment) (*appsv1.Deployment, error) { + namespace := amfDeployment.Namespace + instanceName := amfDeployment.Name + spec := amfDeployment.Spec replicas, resourceRequirements, err := createResourceRequirements(spec) if err != nil { return nil, err } - networkAttachmentDefinitionNetworks, err := createNetworkAttachmentDefinitionNetworks(nfDeployment.Name, &spec) + networkAttachmentDefinitionNetworks, err := createNetworkAttachmentDefinitionNetworks(amfDeployment.Name, &spec) if err != nil { return nil, err } @@ -132,9 +132,9 @@ func createDeployment(log logr.Logger, configMapVersion string, nfDeployment *ne return deployment, nil } -func createService(nfDeployment *nephiov1alpha1.NFDeployment) *apiv1.Service { - namespace := nfDeployment.Namespace - instanceName := nfDeployment.Name +func createService(amfDeployment *nephiov1alpha1.NFDeployment) *apiv1.Service { + namespace := amfDeployment.Namespace + instanceName := amfDeployment.Name labels := map[string]string{ "name": instanceName, @@ -160,13 +160,13 @@ func createService(nfDeployment *nephiov1alpha1.NFDeployment) *apiv1.Service { return service } -func createConfigMap(log logr.Logger, nfDeployment *nephiov1alpha1.NFDeployment) (*apiv1.ConfigMap, error) { - namespace := nfDeployment.Namespace - instanceName := nfDeployment.Name +func createConfigMap(log logr.Logger, amfDeployment *nephiov1alpha1.NFDeployment) (*apiv1.ConfigMap, error) { + namespace := amfDeployment.Namespace + instanceName := amfDeployment.Name - n2ip, err := controllers.GetFirstInterfaceConfigIPv4(nfDeployment.Spec.Interfaces, "n2") + n2ip, err := controllers.GetFirstInterfaceConfigIPv4(amfDeployment.Spec.Interfaces, "n2") if err != nil { - log.Error(err, "Interface N2 not found in NFDeployment Spec") + log.Error(err, "Interface N2 not found in AMF NFDeployment Spec") return nil, err } @@ -177,7 +177,7 @@ func createConfigMap(log logr.Logger, nfDeployment *nephiov1alpha1.NFDeployment) configuration, err := renderConfigurationTemplate(templateValues) if err != nil { - log.Error(err, "Could not render NF configuration template.") + log.Error(err, "Could not render AMF configuration template") return nil, err } @@ -199,7 +199,7 @@ func createConfigMap(log logr.Logger, nfDeployment *nephiov1alpha1.NFDeployment) return configMap, nil } -func createResourceRequirements(nfDeploymentSpec nephiov1alpha1.NFDeploymentSpec) (int32, *apiv1.ResourceRequirements, error) { +func createResourceRequirements(amfDeploymentSpec nephiov1alpha1.NFDeploymentSpec) (int32, *apiv1.ResourceRequirements, error) { // TODO: Requirements should be calculated based on DL, UL // TODO: increase number of recpicas based on NFDeployment.Capacity.MaxSessions @@ -211,7 +211,7 @@ func createResourceRequirements(nfDeploymentSpec nephiov1alpha1.NFDeploymentSpec var memoryLimit string var memoryRequest string - if nfDeploymentSpec.Capacity.MaxSubscribers > 1000 { + if amfDeploymentSpec.Capacity.MaxSubscribers > 1000 { cpuLimit = "300m" memoryLimit = "256Mi" cpuRequest = "300m" @@ -237,8 +237,8 @@ func createResourceRequirements(nfDeploymentSpec nephiov1alpha1.NFDeploymentSpec return replicas, &resources, nil } -func createNetworkAttachmentDefinitionNetworks(templateName string, nfDeploymentSpec *nephiov1alpha1.NFDeploymentSpec) (string, error) { +func createNetworkAttachmentDefinitionNetworks(templateName string, amfDeploymentSpec *nephiov1alpha1.NFDeploymentSpec) (string, error) { return controllers.CreateNetworkAttachmentDefinitionNetworks(templateName, map[string][]nephiov1alpha1.InterfaceConfig{ - "n2": controllers.GetInterfaceConfigs(nfDeploymentSpec.Interfaces, "n2"), + "n2": controllers.GetInterfaceConfigs(amfDeploymentSpec.Interfaces, "n2"), }) } diff --git a/controllers/nf/reconciler.go b/controllers/nf/reconciler.go index d54266b..e9b23da 100644 --- a/controllers/nf/reconciler.go +++ b/controllers/nf/reconciler.go @@ -50,12 +50,13 @@ func (r *NFDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error { // +kubebuilder:rbac:groups=workload.nephio.org,resources=nfdeployments,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=workload.nephio.org,resources=nfdeployments/status,verbs=get;update;patch +// +kubebuilder:rbac:groups="ref.nephio.org",resources=configs,verbs=get;list;watch +// +kubebuilder:rbac:groups="k8s.cni.cncf.io",resources=network-attachment-definitions,verbs=get;list;watch // +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get // +kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch // +kubebuilder:rbac:groups="",resources=configmaps;services,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch -// +kubebuilder:rbac:groups="k8s.cni.cncf.io",resources=network-attachment-definitions,verbs=get;list;watch // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. diff --git a/controllers/nf/smf/reconciler.go b/controllers/nf/smf/reconciler.go index d03a284..5afb694 100644 --- a/controllers/nf/smf/reconciler.go +++ b/controllers/nf/smf/reconciler.go @@ -18,8 +18,10 @@ package smf import ( "context" + "fmt" "time" + "github.com/go-logr/logr" nephiov1alpha1 "github.com/nephio-project/api/nf_deployments/v1alpha1" refv1alpha1 "github.com/nephio-project/api/references/v1alpha1" "github.com/nephio-project/free5gc/controllers" @@ -35,45 +37,60 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -// Reconciles a SMFDeployment resource +// Reconciles a SMF NFDeployment resource type SMFDeploymentReconciler struct { client.Client Scheme *runtime.Scheme } // Fetch all SMF ConfigRefs -func (r *SMFDeploymentReconciler) GetAllConfigRefs(ctx context.Context, smfDeployment *nephiov1alpha1.NFDeployment, namespace types.NamespacedName) ([]*refv1alpha1.Config, error) { - var ret []*refv1alpha1.Config +func (r *SMFDeploymentReconciler) GetAllConfigRefs(ctx context.Context, log logr.Logger, smfDeployment *nephiov1alpha1.NFDeployment, namespace types.NamespacedName) ([]*refv1alpha1.Config, error) { + var configRefs []*refv1alpha1.Config + for _, objRef := range smfDeployment.Spec.ParametersRefs { - cfgRef := &refv1alpha1.Config{} - if err := r.Client.Get(ctx, types.NamespacedName{Name: *objRef.Name, Namespace: namespace.Namespace}, cfgRef); err != nil { - return ret, err + configRef := new(refv1alpha1.Config) + if err := r.Client.Get(ctx, types.NamespacedName{Name: *objRef.Name, Namespace: namespace.Namespace}, configRef); err != nil { + return configRefs, err + } + + var duplicate bool + for _, configRef_ := range configRefs { + if (configRef_.Namespace == configRef.Namespace) && (configRef_.Name == configRef.Name) { + duplicate = true + break + } } - ret = append(ret, cfgRef) + if duplicate { + log.Info(fmt.Sprintf("Duplicate entry in ConfigRefs: %s/%s", configRef.Namespace, configRef.Name)) + continue + } + + configRefs = append(configRefs, configRef) } - return ret, nil + + return configRefs, nil } // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. // TODO(user): Modify the Reconcile function to compare the state specified by -// the SMFDeployment object against the actual cluster state, and then +// the SMF NFDeployment object against the actual cluster state, and then // perform operations to make the cluster state reflect the state specified by // the user. // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile func (r *SMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx).WithValues("SMFDeployment", req.NamespacedName) + log := log.FromContext(ctx).WithValues("NFDeployment", req.NamespacedName, "NF", "SMF") smfDeployment := new(nephiov1alpha1.NFDeployment) err := r.Client.Get(ctx, req.NamespacedName, smfDeployment) if err != nil { if k8serrors.IsNotFound(err) { - log.Info("SMFDeployment resource not found, ignoring because object must be deleted") + log.Info("SMF NFDeployment resource not found, ignoring because object must be deleted") return reconcile.Result{}, nil } - log.Error(err, "Failed to get SMFDeployment") + log.Error(err, "Failed to get SMF NFDeployment") return reconcile.Result{}, err } namespace := smfDeployment.Namespace @@ -124,7 +141,7 @@ func (r *SMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques } var smfConfigRefs []*refv1alpha1.Config - if smfConfigRefs, err = r.GetAllConfigRefs(ctx, smfDeployment, req.NamespacedName); err != nil { + if smfConfigRefs, err = r.GetAllConfigRefs(ctx, log, smfDeployment, req.NamespacedName); err != nil { log.Info("Not all config references found... rerun reconcile") return reconcile.Result{}, err } @@ -132,7 +149,7 @@ func (r *SMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques if configMap, err := createConfigMap(log, smfDeployment, smfConfigRefs); err == nil { if !configMapFound { log.Info("Creating ConfigMap", "ConfigMap.namespace", configMap.Namespace, "ConfigMap.name", configMap.Name) - // Set the controller reference, specifying that SMFDeployment controls the underlying ConfigMap + // Set the controller reference, specifying that SMF NFDeployment controls the underlying ConfigMap if err := ctrl.SetControllerReference(smfDeployment, configMap, r.Scheme); err != nil { log.Error(err, "Got error while setting Owner reference on ConfigMap", "ConfigMap.namespace", configMap.Namespace, "ConfigMap.name", configMap.Name) } @@ -151,9 +168,9 @@ func (r *SMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques if !serviceFound { service := createService(smfDeployment) - log.Info("Creating SMFDeployment service", "Service.namespace", service.Namespace, "Service.name", service.Name) + log.Info("Creating SMF NFDeployment service", "Service.namespace", service.Namespace, "Service.name", service.Name) - // Set the controller reference, specifying that SMFDeployment controls the underlying Service + // Set the controller reference, specifying that SMF NFDeployment controls the underlying Service if err := ctrl.SetControllerReference(smfDeployment, service, r.Scheme); err != nil { log.Error(err, "Got error while setting Owner reference on SMF Service", "Service.namespace", service.Namespace, "Service.name", service.Name) } @@ -168,7 +185,7 @@ func (r *SMFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques if !deploymentFound { // Only create Deployment in case all required NADs are present. Otherwise Requeue in 10 sec. if ok := controllers.ValidateNetworkAttachmentDefinitions(ctx, r.Client, log, smfDeployment.Kind, deployment); ok { - // Set the controller reference, specifying that SMFDeployment controls the underlying Deployment + // Set the controller reference, specifying that SMF NFDeployment controls the underlying Deployment if err := ctrl.SetControllerReference(smfDeployment, deployment, r.Scheme); err != nil { log.Error(err, "Got error while setting Owner reference on Deployment", "Deployment.namespace", deployment.Name, "Deployment.name", deployment.Name) } diff --git a/controllers/nf/smf/resources.go b/controllers/nf/smf/resources.go index d0b6af9..c8c2503 100644 --- a/controllers/nf/smf/resources.go +++ b/controllers/nf/smf/resources.go @@ -173,7 +173,7 @@ func createConfigMap(log logr.Logger, smfDeployment *nephiov1alpha1.NFDeployment n4ip, err := controllers.GetFirstInterfaceConfigIPv4(smfDeployment.Spec.Interfaces, "n4") if err != nil { - log.Error(err, "Interface N4 not found in SMFDeployment Spec") + log.Error(err, "Interface N4 not found in SMF NFDeployment Spec") return nil, err } @@ -182,44 +182,44 @@ func createConfigMap(log logr.Logger, smfDeployment *nephiov1alpha1.NFDeployment PFCP_IP: n4ip, } - if upfDeployments, err := extractConfigRefUPFDeployment(smfConfigRefs); err != nil { - log.Error(err, "Failed to extract UPFDeployment from ConfigRefs") - return nil, err - } else { + if upfDeployments, err := extractConfigRefUPFDeployments(smfConfigRefs); err == nil { for _, upfDeployment := range upfDeployments { - upfCfg := UpfPeerConfigTemplate{} - upfCfg.Name = upfDeployment.ObjectMeta.Name + var upfConfig UpfPeerConfigTemplate + upfConfig.Name = upfDeployment.ObjectMeta.Name if upfN4Ip, err := controllers.GetFirstInterfaceConfigIPv4(upfDeployment.Spec.Interfaces, "n4"); err != nil { - log.Error(err, fmt.Sprintf("Interface N4 not found in UPFDeployment Spec %v\n", upfDeployment.Spec)) + log.Error(err, fmt.Sprintf("Interface N4 not found in UPF NFDeployment Spec %v", upfDeployment.Spec)) return nil, err } else { - upfCfg.N4IP = upfN4Ip + upfConfig.N4IP = upfN4Ip } if upfN3Ip, err := controllers.GetFirstInterfaceConfigIPv4(upfDeployment.Spec.Interfaces, "n3"); err != nil { - log.Error(err, fmt.Sprintf("Interface N3 not found in UPFDeployment Spec %v\n", upfDeployment.Spec)) + log.Error(err, fmt.Sprintf("Interface N3 not found in UPF NFDeployment Spec %v", upfDeployment.Spec)) return nil, err } else { - upfCfg.N3IP = upfN3Ip + upfConfig.N3IP = upfN3Ip } if upfN6Cfg, ok := getNetworkInstances(&upfDeployment.Spec, "n6"); !ok { - log.Error(err, fmt.Sprintf("N6 Interface not found in UPFDeployment Spec %v\n", upfDeployment.Spec)) - return nil, errors.New("No N6 intefaces in UPFDeployment Spec.") + log.Error(err, fmt.Sprintf("N6 Interface not found in UPF NFDeployment Spec %v", upfDeployment.Spec)) + return nil, errors.New("No N6 intefaces in UPF NFDeployment Spec") } else { - upfCfg.N6Cfg = upfN6Cfg + upfConfig.N6Cfg = upfN6Cfg } - templateValues.UPF_LIST = append(templateValues.UPF_LIST, upfCfg) + templateValues.UPF_LIST = append(templateValues.UPF_LIST, upfConfig) } + } else { + log.Error(err, "Failed to extract UPF NFDeployment from ConfigRefs") + return nil, err } configuration, err := renderConfigurationTemplate(templateValues) if err != nil { - log.Error(err, "Could not render SMF configuration template.") + log.Error(err, "Could not render SMF configuration template") return nil, err } ueRoutingConfiguration, err := renderUeRoutingConfigurationTemplate(templateValues) if err != nil { - log.Error(err, "Could not render SMF UE routing configuration template.") + log.Error(err, "Could not render SMF UE routing configuration template") return nil, err } @@ -294,35 +294,34 @@ func getNetworkInstances(upfDeploymentSpec *nephiov1alpha1.NFDeploymentSpec, int } } - if len(networkInstances) == 0 { - return networkInstances, false - } else { - return networkInstances, true - } + return networkInstances, len(networkInstances) != 0 } -func extractConfigRefUPFDeployment(refs []*refv1alpha1.Config) ([]nephiov1alpha1.NFDeployment, error) { - var ret []nephiov1alpha1.NFDeployment - for _, ref := range refs { - var b []byte - if ref.Spec.Config.Object == nil { - b = ref.Spec.Config.Raw +func extractConfigRefUPFDeployments(configRegs []*refv1alpha1.Config) ([]nephiov1alpha1.NFDeployment, error) { + var upfDeployments []nephiov1alpha1.NFDeployment + + for _, configRef := range configRegs { + var raw []byte + if configRef.Spec.Config.Object == nil { + raw = configRef.Spec.Config.Raw } else { - if ref.Spec.Config.Object.GetObjectKind().GroupVersionKind() == nephiov1alpha1.NFDeploymentGroupVersionKind { + if configRef.Spec.Config.Object.GetObjectKind().GroupVersionKind() == nephiov1alpha1.NFDeploymentGroupVersionKind { var err error - if b, err = json.Marshal(ref.Spec.Config.Object); err != nil { + if raw, err = json.Marshal(configRef.Spec.Config.Object); err != nil { return nil, err } } else { continue } } - upfDeployment := &nephiov1alpha1.NFDeployment{} - if err := json.Unmarshal(b, upfDeployment); err != nil { - return nil, err + + var upfDeployment nephiov1alpha1.NFDeployment + if err := json.Unmarshal(raw, &upfDeployment); err == nil { + upfDeployments = append(upfDeployments, upfDeployment) } else { - ret = append(ret, *upfDeployment) + return nil, err } } - return ret, nil + + return upfDeployments, nil } diff --git a/controllers/nf/upf/reconciler.go b/controllers/nf/upf/reconciler.go index 165e263..fdc7840 100644 --- a/controllers/nf/upf/reconciler.go +++ b/controllers/nf/upf/reconciler.go @@ -33,7 +33,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -// Reconciles a UPFDeployment resource +// Reconciles a UPF NFDeployment resource type UPFDeploymentReconciler struct { client.Client Scheme *runtime.Scheme @@ -49,16 +49,16 @@ type UPFDeploymentReconciler struct { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile func (r *UPFDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx).WithValues("NFDeployment", req.NamespacedName) + log := log.FromContext(ctx).WithValues("NFDeployment", req.NamespacedName, "NF", "UPF") nfDeployment := new(nephiov1alpha1.NFDeployment) err := r.Client.Get(ctx, req.NamespacedName, nfDeployment) if err != nil { if k8serrors.IsNotFound(err) { - log.Info("NFDeployment resource not found, ignoring because object must be deleted") + log.Info("UPF NFDeployment resource not found, ignoring because object must be deleted") return reconcile.Result{}, nil } - log.Error(err, "Failed to get NFDeployment") + log.Error(err, "Failed to get UPF NFDeployment") return reconcile.Result{}, err } diff --git a/controllers/nf/upf/resources.go b/controllers/nf/upf/resources.go index 79f8a25..e6e4b68 100644 --- a/controllers/nf/upf/resources.go +++ b/controllers/nf/upf/resources.go @@ -145,19 +145,19 @@ func createConfigMap(log logr.Logger, upfDeployment *nephiov1alpha1.NFDeployment n4ip, err := controllers.GetFirstInterfaceConfigIPv4(upfDeployment.Spec.Interfaces, "n4") if err != nil { - log.Error(err, "Interface N4 not found in UPFDeployment Spec") + log.Error(err, "Interface N4 not found in UPF NFDeployment Spec") return nil, err } n3ip, err := controllers.GetFirstInterfaceConfigIPv4(upfDeployment.Spec.Interfaces, "n3") if err != nil { - log.Error(err, "Interface N3 not found in UPFDeployment Spec") + log.Error(err, "Interface N3 not found in UPF NFDeployment Spec") return nil, err } n6ip, err := controllers.GetFirstInterfaceConfig(upfDeployment.Spec.Interfaces, "n6") if err != nil { - log.Error(err, "Interface N6 not found in UPFDeployment Spec") + log.Error(err, "Interface N6 not found in UPF NFDeployment Spec") return nil, err } @@ -170,19 +170,19 @@ func createConfigMap(log logr.Logger, upfDeployment *nephiov1alpha1.NFDeployment if n6Instances, ok := getNetworkInstances(upfDeployment.Spec, "n6"); ok { templateValues.N6cfg = n6Instances } else { - log.Error(err, "No N6 interface in UPFDeployment Spec.") - return nil, errors.New("No N6 intefaces in UPFDeployment Spec.") + log.Error(err, "No N6 interface in UPF NFDeployment Spec") + return nil, errors.New("No N6 intefaces in UPF NFDeployment Spec") } configuration, err := renderConfigurationTemplate(templateValues) if err != nil { - log.Error(err, "Could not render UPF configuration template.") + log.Error(err, "Could not render UPF configuration template") return nil, err } wrapperScript, err := renderWrapperScriptTemplate(templateValues) if err != nil { - log.Error(err, "Could not render UPF wrapper script template.") + log.Error(err, "Could not render UPF wrapper script template") return nil, err } diff --git a/free5gc-images/Makefile b/free5gc-images/Makefile index 1d93a85..80da366 100644 --- a/free5gc-images/Makefile +++ b/free5gc-images/Makefile @@ -1,7 +1,7 @@ FREE5GC_VERSION ?= 3.2.1 IMG_REGISTRY ?= docker.io/nephio BASE_IMAGE ?= alpine:3.18.0 -BUILDER_IMAGE ?= golang:1.20.5 +BUILDER_IMAGE ?= golang:1.21.6 ifeq ($(NO_CACHE),true) BUILD_ARGS=--no-cache diff --git a/test/amf1.yaml b/test/amf1.yaml index 68d6373..a1cb1c8 100644 --- a/test/amf1.yaml +++ b/test/amf1.yaml @@ -8,7 +8,7 @@ metadata: config.kubernetes.io/local-config: "false" spec: - provider: "amf.free5gc.nephio.org" + provider: amf.free5gc.io capacity: maxSubscribers: 1000 interfaces: diff --git a/test/configref2.yaml b/test/configref2.yaml deleted file mode 100644 index 1a645ce..0000000 --- a/test/configref2.yaml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: ref.nephio.org/v1alpha1 -kind: Config -metadata: - name: smf-config-ref-2 - namespace: free5gc -spec: - config: - apiVersion: workload.nephio.org/v1alpha1 - kind: UPFDeployment - metadata: - name: free5gc-upf-2 - namespace: upf-2 - spec: - capacity: - maxUplinkThroughput: 1G - maxDownlinkThroughput: 10G - interfaces: - - name: n6 - ipv4: - address: 10.10.13.100/24 - gateway: 10.10.13.1 - - name: n3 - ipv4: - address: 10.10.15.100/24 - gateway: 10.10.15.1 - - name: n4 - ipv4: - address: 10.10.14.100/24 - gateway: 10.10.14.1 - networkInstances: - - name: private-network - interfaces: - - n6 - dataNetworks: - - name: junk - pool: - - prefix: 100.200.0.0/16 diff --git a/test/smf1.yaml b/test/smf1.yaml index c7b3f71..dada314 100644 --- a/test/smf1.yaml +++ b/test/smf1.yaml @@ -8,7 +8,7 @@ metadata: config.kubernetes.io/local-config: "false" spec: - provider: "smf.free5gc.nephio.org" + provider: smf.free5gc.io capacity: maxSessions: 5000 maxNFConnections: 100 @@ -25,8 +25,12 @@ spec: dataNetworks: - name: internet pool: - - prefix: "10.200.50.0/24" + - prefix: 10.200.50.0/24 parametersRefs: - - apiVersion: "ref.nephio.org/v1alpha1" - kind: Config - name: smf-config-ref + - apiVersion: ref.nephio.org/v1alpha1 + kind: Config + name: upf1-config-ref +# Uncomment to test duplication avoidance: +# - apiVersion: ref.nephio.org/v1alpha1 +# kind: Config +# name: upf1-config-ref diff --git a/test/configref1.yaml b/test/upf1-config-ref.yaml similarity index 94% rename from test/configref1.yaml rename to test/upf1-config-ref.yaml index 36f967d..042261e 100644 --- a/test/configref1.yaml +++ b/test/upf1-config-ref.yaml @@ -1,15 +1,17 @@ apiVersion: ref.nephio.org/v1alpha1 kind: Config + metadata: - name: smf-config-ref namespace: free5gc + name: upf1-config-ref + spec: config: apiVersion: workload.nephio.org/v1alpha1 kind: NFDeployment metadata: + namespace: free5gc name: free5gc-upf-1 - namespace: upf-1 spec: capacity: maxUplinkThroughput: 1G diff --git a/test/upf1.yaml b/test/upf1.yaml index b6ea7cf..2bc5f5c 100644 --- a/test/upf1.yaml +++ b/test/upf1.yaml @@ -8,7 +8,7 @@ metadata: config.kubernetes.io/local-config: "false" spec: - provider: "upf.free5gc.nephio.org" + provider: upf.free5gc.io capacity: maxUplinkThroughput: 3G maxDownlinkThroughput: 1G diff --git a/test/upf2-n3.yaml b/test/upf2-n3.yaml deleted file mode 100644 index 795bcfa..0000000 --- a/test/upf2-n3.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Source: free5gc/charts/free5gc-upf/templates/upf-n3-nad.yaml -# -# Software Name : towards5gs-helm -# SPDX-FileCopyrightText: Copyright (c) 2021 Orange -# SPDX-License-Identifier: Apache-2.0 -# -# This software is distributed under the Apache License 2.0, -# the text of which is available at https://github.com/Orange-OpenSource/towards5gs-helm/blob/main/LICENSE -# or see the "LICENSE" file for more details. -# -# Author: Abderaouf KHICHANE, Ilhem FAJJARI, Ayoub BOUSSELMI -# Software description: An open-source project providing Helm charts to deploy 5G components (Core + RAN) on top of Kubernetes -# -apiVersion: k8s.cni.cncf.io/v1 -kind: NetworkAttachmentDefinition - -metadata: - namespace: free5gc - name: free5gc-upf-2-n3 - -spec: - config: '{ - "cniVersion": "0.3.1", - "plugins": [ - { - "type": "macvlan", - "capabilities": { "ips": true }, - "master": "eth0", - "mode": "bridge", - "ipam": { - "type": "static", - "routes": [] - } - }, { - "capabilities": { "mac": true }, - "type": "tuning" - } - ] - }' diff --git a/test/upf2-n4.yaml b/test/upf2-n4.yaml deleted file mode 100644 index 976726a..0000000 --- a/test/upf2-n4.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Source: free5gc/charts/free5gc-upf/templates/upf-n4-nad.yaml -# -# Software Name : towards5gs-helm -# SPDX-FileCopyrightText: Copyright (c) 2021 Orange -# SPDX-License-Identifier: Apache-2.0 -# -# This software is distributed under the Apache License 2.0, -# the text of which is available at https://github.com/Orange-OpenSource/towards5gs-helm/blob/main/LICENSE -# or see the "LICENSE" file for more details. -# -# Author: Abderaouf KHICHANE, Ilhem FAJJARI, Ayoub BOUSSELMI -# Software description: An open-source project providing Helm charts to deploy 5G components (Core + RAN) on top of Kubernetes -# -apiVersion: k8s.cni.cncf.io/v1 -kind: NetworkAttachmentDefinition - -metadata: - namespace: free5gc - name: free5gc-upf-2-n4 - -spec: - config: '{ - "cniVersion": "0.3.1", - "plugins": [ - { - "type": "macvlan", - "capabilities": { "ips": true }, - "master": "eth0", - "mode": "bridge", - "ipam": { - "type": "static", - "routes": [] - } - }, { - "capabilities": { "mac": true }, - "type": "tuning" - } - ] - }' diff --git a/test/upf2-n6.yaml b/test/upf2-n6.yaml deleted file mode 100644 index a167f32..0000000 --- a/test/upf2-n6.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Source: free5gc/charts/free5gc-upf/templates/upf-n6-nad.yaml -# -# Software Name : towards5gs-helm -# SPDX-FileCopyrightText: Copyright (c) 2021 Orange -# SPDX-License-Identifier: Apache-2.0 -# -# This software is distributed under the Apache License 2.0, -# the text of which is available at https://github.com/Orange-OpenSource/towards5gs-helm/blob/main/LICENSE -# or see the "LICENSE" file for more details. -# -# Author: Abderaouf KHICHANE, Ilhem FAJJARI, Ayoub BOUSSELMI -# Software description: An open-source project providing Helm charts to deploy 5G components (Core + RAN) on top of Kubernetes -# -apiVersion: k8s.cni.cncf.io/v1 -kind: NetworkAttachmentDefinition - -metadata: - namespace: free5gc - name: free5gc-upf-2-n6 - -spec: - config: '{ - "cniVersion": "0.3.1", - "plugins": [ - { - "type": "macvlan", - "capabilities": { "ips": true }, - "master": "eno1", - "mode": "bridge", - "ipam": { - "type": "static", - "routes": [ - ] - } - }, { - "capabilities": { "mac": true }, - "type": "tuning" - } - ] - }' diff --git a/test/upf2.yaml b/test/upf2.yaml deleted file mode 100644 index b5d8976..0000000 --- a/test/upf2.yaml +++ /dev/null @@ -1,44 +0,0 @@ -apiVersion: workload.nephio.org/v1alpha1 -kind: UPFDeployment - -metadata: - namespace: free5gc - name: upf-2 - annotations: - config.kubernetes.io/local-config: "false" - -spec: - capacity: - maxUplinkThroughput: 10G - maxDownlinkThroughput: 10G - interfaces: - - name: n3 - ipv4: - address: 13.1.0.2/24 - gateway: 13.1.0.1 - vlanID: 13 - - name: n4 - ipv4: - address: 14.1.0.2/24 - gateway: 14.1.0.1 - vlanID: 14 - - name: n6 - ipv4: - address: 16.1.0.2/24 - gateway: 16.1.0.1 - vlanID: 16 - networkInstances: - - name: vpc-ran - interfaces: - - n3 - - name: vpc-internal - interfaces: - - n4 - - name: vpc-internet - interfaces: - - n6 - dataNetworks: - - name: internet - pool: - - prefix: 10.1.0.0/16 - configRefs: