Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • eclipse-research-labs/nemo-project/nemo-infrastructure-management/federated-meta-network-cluster-controller/multi-domain-l2s-m
1 result
Show changes
Commits on Source (278)
Showing
with 1617 additions and 27 deletions
CONTROLLER_IP=10.152.183.155
CONTROLLER_PORT=8181
SWITCHES_NAMESPACE=l2sm-system
name: Sync to GitLab
on:
push:
branches:
- nemo
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout GitHub repository
uses: actions/checkout@v3
with:
ref: nemo
- name: Configure Git
run: |
git config user.name "Tjaarda1"
git config user.email "100383348@alumnos.uc3m.es"
- name: Add GitLab remote
run: |
git remote add gitlab https://oauth2:${{ secrets.GITLAB_TOKEN }}@gitlab.eclipse.org/eclipse-research-labs/nemo-project/nemo-infrastructure-management/federated-meta-network-cluster-controller/multi-domain-l2s-m.git
- name: Push to GitLab
run: |
git push gitlab nemo:development
.vscode
tls.b64
bin/
\ No newline at end of file
{
"version": "0.2.0",
"configurations": [
{
"name": "Kopf Run: l2sm-operator",
"type": "node-terminal",
"request": "launch",
"command": "kopf run ${workspaceFolder}/src/operator/l2sm-operator.py",
"env": {
"CONTROLLER_IP": "10.152.183.42",
"DATABASE_IP": "10.152.183.70",
"MYSQL_USER": "l2sm",
"MYSQL_PASSWORD": "l2sm",
"MYSQL_DATABASE": "l2sm",
"NODE_NAME": "l2sm1"
}
}
]
}
{
"java.configuration.updateBuildConfiguration": "interactive"
}
\ No newline at end of file
# Copyright 2024 Universidad Carlos III de Madrid
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Build the manager binary
FROM golang:1.21 AS builder
ARG TARGETOS
ARG TARGETARCH
WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download
# Copy the go source
COPY cmd/main.go cmd/main.go
COPY api/ api/
COPY internal/ internal/
# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# 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=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532
ENTRYPOINT ["/manager"]
# Build the manager binary
FROM --platform=${BUILDPLATFORM} golang:1.21 AS builder
ARG TARGETOS
ARG TARGETARCH
WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download
# Copy the go source
COPY cmd/main.go cmd/main.go
COPY api/ api/
COPY internal/ internal/
# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# 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=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532
ENTRYPOINT ["/manager"]
# Image URL to use all building/pushing image targets
IMG ?= alexdecb/l2sm-controller-manager:2.7.1
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.29.0
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif
# CONTAINER_TOOL defines the container tool to be used for building images.
# Be aware that the target commands are only tested with Docker which is
# scaffolded by default. However, you might want to replace it to use other
# tools. (i.e. podman)
CONTAINER_TOOL ?= sudo docker
# Setting SHELL to bash allows bash commands to be executed by recipes.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec
REPOSITORY=L2S-M
.PHONY: all
all: build
##@ General
# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk command is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Development
.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-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.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...
.PHONY: vet
vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
go test ./test/e2e/ -v -ginkgo.v
.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter & yamllint
$(GOLANGCI_LINT) run
.PHONY: lint-fix
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
$(GOLANGCI_LINT) run --fix
##@ Build
.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
go build -o bin/manager cmd/main.go
.PHONY: run
include .env
export $(shell sed 's/=.*//' .env)
run: manifests generate fmt vet ## Run a controller from your host.
go run ./cmd/main.go
# If you wish to build the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
$(CONTAINER_TOOL) build -t ${IMG} .
.PHONY: docker-push
docker-push: ## Push docker image with the manager.
$(CONTAINER_TOOL) push ${IMG}
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
.PHONY: docker-buildx
docker-buildx: ## Build and push docker image for the manager for cross-platform support
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
- $(CONTAINER_TOOL) buildx create --name project-v3-builder
$(CONTAINER_TOOL) buildx use project-v3-builder
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
- $(CONTAINER_TOOL) buildx rm project-v3-builder
rm Dockerfile.cross
.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
echo "" > deployments/l2sm-deployment.yaml
echo "---" >> deployments/l2sm-deployment.yaml # Add a document separator before appending
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default >> deployments/l2sm-deployment.yaml
$(KUSTOMIZE) build config/tmp >> deployments/l2sm-deployment.yaml
##@ Deployment
ifndef ignore-not-found
ignore-not-found = false
endif
.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: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -
$(KUSTOMIZE) build config/tmp | $(KUBECTL) apply -f -
.PHONY: undeploy
undeploy: kustomize ## Undeploy controller 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/tmp | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
.PHONY: webhook-certs
webhook-certs: ## generate self-signed cert and key for local webhook development
mkdir -p /tmp/k8s-webhook-server/serving-certs
openssl req -x509 -newkey rsa:2048 -nodes -keyout /tmp/k8s-webhook-server/serving-certs/tls.key -out /tmp/k8s-webhook-server/serving-certs/tls.crt -days 365 -config ./config/dev/openssl.cnf -batch -subj '/CN=local-webhook'
cat /tmp/k8s-webhook-server/serving-certs/tls.crt | base64 -w0 > /tmp/k8s-webhook-server/tls.b64
# $(eval B64_CERT := $(shell cat /tmp/k8s-webhook-server/tls.b64))
# echo $(B64_CERT)
# cat /tmp/k8s-webhook-server/tls.b64
# openssl req -x509 \
# -newkey rsa:2048 \
# -nodes \
# -keyout /tmp/k8s-webhook-server/serving-certs/tls.key \
# -out /tmp/k8s-webhook-server/serving-certs/tls.crt \
# -days 365 \
# -subj '/CN=local-webhook'
##@ Webhook
.PHONY: deploy-dev
deploy-dev: webhook-certs manifests kustomize ## Deploy validating and mutating webhooks to the K8s cluster specified in ~/.kube/config.
sed -i'' -e 's/caBundle: .*/caBundle: $(shell cat /tmp/k8s-webhook-server/tls.b64)/' ./config/dev/webhookcainjection_patch.yaml
$(KUSTOMIZE) build config/dev | $(KUBECTL) apply -f -
.PHONY: undeploy-dev
undeploy-dev: kustomize ## Undeploy validating and mutating webhooks from the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/dev | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
# Define file extensions for various formats
FILES := $(shell find . -type f \( -name "*.go" -o -name "*.json" -o -name "*.yaml" -o -name "*.yml" -o -name "*.md" \))
# Install the addlicense tool if not installed
.PHONY: install-tools
install-tools:
@go install github.com/google/addlicense@latest
# Add license headers to the files
.PHONY: add-license
add-license: install-tools
@for file in $(FILES); do \
addlicense -f ./hack/LICENSE.txt -l apache "$${file}"; \
done
##@ Dependencies
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)
## Tool Binaries
KUBECTL ?= kubectl
KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION)
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION)
ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION)
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION)
## Tool Versions
KUSTOMIZE_VERSION ?= v5.3.0
CONTROLLER_TOOLS_VERSION ?= v0.14.0
ENVTEST_VERSION ?= latest
GOLANGCI_LINT_VERSION ?= v1.54.2
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))
.PHONY: envtest
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
$(ENVTEST): $(LOCALBIN)
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION})
# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary (ideally with version)
# $2 - package url which can be installed
# $3 - specific version of package
define go-install-tool
@[ -f $(1) ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv "$$(echo "$(1)" | sed "s/-$(3)$$//")" $(1) ;\
}
endef
# Code generated by tool. DO NOT EDIT.
# This file is used to track the info used to scaffold your project
# and allow the plugins properly work.
# More info: https://book.kubebuilder.io/reference/project-config.html
domain: l2sm.k8s.local
layout:
- go.kubebuilder.io/v4
projectName: controllermanager
repo: github.com/Networks-it-uc3m/L2S-M
resources:
- api:
crdVersion: v1
namespaced: true
controller: true
domain: l2sm.k8s.local
group: l2sm
kind: L2Network
path: github.com/Networks-it-uc3m/L2S-M/api/v1
version: v1
- controller: true
group: core
kind: Pod
path: k8s.io/api/core/v1
version: v1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: l2sm.k8s.local
group: l2sm
kind: NetworkEdgeDevice
path: github.com/Networks-it-uc3m/L2S-M/api/v1
version: v1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: l2sm.k8s.local
group: l2sm
kind: Overlay
path: github.com/Networks-it-uc3m/L2S-M/api/v1
version: v1
webhooks:
defaulting: true
validation: true
webhookVersion: v1
version: "3"
<!---
Copyright 2024 Universidad Carlos III de Madrid
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy
of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
SPDX-License-Identifier: Apache-2.0
-->
# Multi domain L2S-M
# Multi domain L2S-M
Welcome to the official repository of L2S-M, a **Kubernetes operator** that enables virtual networking in K8s clusters.
Link-Layer Secure connectivity for Microservice platforms (L2S-M) is a K8s networking solution that complements the CNI plugin approach of K8s to create and manage virtual networks in K8s clusters. These virtual networks allow workloads (pods) to have isolated link-layer connectivity with other pods in a K8s cluster, regardless of the k8s node where they are actually deployed. L2S-M enables the creation/deletion of virtual networks on-demand, as well as attaching/detaching pods to that networks. The solution is seamlessly integrated within the K8s environment, through a K8s operator:
![alt text](./L2S-M%20core/assets/v1_architecture.png?raw=true)
![alt text](./assets/v1_architecture.png?raw=true)
L2S-M provides its intended functionalities using a programmable data-plane based on Software Defined Networking (SDN), which in turn provides a high degree of flexibility to dynamically incorporate new application and/or network configurations into K8s clusters. Moreover, L2S-M has been designed to flexibly accommodate various deployment options, ranging from small K8s clusters to those with a high number of distributed nodes.
The main K8s interface of pods remains intact (provided by a CNI plugin), retaining the compatibility with all the standard K8s elements (e.g., services, connectivity through the main interface, etc.). Moreover, the solution has the potential to be used for inter-cluster communications to support scenarios where network functions are spread through multiple distributed infrastructures (this is still a work in progress).
The figure outlines the design of L2S-M. See [how L2S-M works](./L2S-M%20core/L2S-M/additional-info/) to read further details on the L2S-M solution.
The figure outlines the design of L2S-M. See [how L2S-M works](./additional-info/) to read further details on the L2S-M solution.
If you want to learn how to install L2S-M in your cluster, see the [installation guide](./L2S-M%20core/deployments) of this repository to start its installation.
If you want to learn how to install L2S-M in your cluster, see the [installation guide](./deployments) of this repository to start its installation.
Did you already install the operator and you cannot wait to start building your own virtual networks in your K8s cluster? Check out our [ping-pong](./L2S-M%20core/examples/ping-pong) example!
Did you already install the operator and you cannot wait to start building your own virtual networks in your K8s cluster? Check out our [general usage guide](./additional-info/general-use.md)! If you're more interested in seeing a simple working example, you can start out with the [ping pong example](./examples/ping-pong/).
If you want more information about the original idea of L2S-M and its initial design, you can check our latest publication in the [IEEE Network journal](https://ieeexplore.ieee.org/document/9740640):
......@@ -39,12 +22,15 @@ If you want more information about the original idea of L2S-M and its initial de
Did you like L2S-M and want to use it in your K8s infrastructure or project? Please, feel free to do so, and don't forget to cite us!
### Demo video
This [video](https://youtube.com/watch?v=Oj2gzm-YxYE&si=bV9eN77wTlXQZY3Y) exemplifies the process to create virtual networks in Kubernetes using the L2S-M open-source software. More concretely, it shows how L2S is used to create a simple content distribution network on a Kubernetes cluster.
### Inter-cluster communications
L2S-M is now capable of managing inter-cluster communications, with custom resources that enable the creation of overlay network topologies and multi domain networks on demand. If you are interested in how these resources are defined, you can check [the provided inter-cluster example](./L2S-M%20core/examples/inter-cluster/) and [the source code of the Custom Resources.](./l2sm-api-resources)
The solution can work jointly with L2S-M or be used standalone through the [Multus CNI](https://github.com/k8snetworkplumbingwg/multus-cni). Details can be checked [here](https://github.com/Networks-it-uc3m/snd-based-inter-cluster-communications/blob/main/README.md).
The solution enables the creation and deletion of virtual link-layer networks to connect application workloads running in different virtualization domains. This way, it supports inter-domain link-layer communications among remote workloads.
One of the most interesting features L2S-M has is that it enables communications among workloads deployed on differente Kubernetes clusters. You can perform the creation and deletion of virtual link-layer networks to connect application workloads running in different virtualization domains. This way, it supports inter-domain link-layer communications among remote workloads.
The solution can work jointly with L2S-M or be used standalone through the [Multus CNI](https://github.com/k8snetworkplumbingwg/multus-cni). Details can be checked [here](./additional-info/inter-cluster.md). Even though the inter-cluster solution is meant to be used via [the multi-domain client](http://github.com/Networks-it-uc3m/l2sm-md), we provide examples of how can you manually set up an entire inter-cluster virtual overlay network in the [inter cluster setup guide](./examples/inter-cluster-setup/). If you have your infrastructure ready, you can go ahead to the [inter cluster networks example](./examples/inter-cluster-network)!
### Additional information about L2S-M
In the [following section](./additional-info) of the repository, you can find a series of documents and slides that provide additional information about L2S-M, including presentations where our solution has been showcased to the public in various events.
......@@ -87,7 +73,7 @@ Do you have any doubts about L2S-M or its installation? Do you want to provide f
### Acknowledgement
The work in this open-source project has partially been supported by the European Horizon NEMO project (grant agreement 101070118), the European Horizon CODECO project (grant agreement 101092696), and by the national 6GINSPIRE project (PID2022-137329OB-C429).
### Other projects where L2S-M has been used
#### Other projects where L2S-M has been used
- H2020 FISHY Project: https://fishy-project.eu (grant agreement 952644)
- True5G Project: (PID2019-108713RB-C52 / AEI / 10.13039/501100011033)
- H2020 Labyrinth project: https://labyrinth2020.eu/ (grant agreement 861696).
File added
# How does L2S-M work?
L2S-M takes a different approach to K8s networking in comparison with other solutions available, which mostly implement CNI plugins to be used as the main connectivity basis for a cluster. L2S-M is deployed as a complementary solution to these CNI Plugins, since it allows the creation and management of virtual networks in a K8s cluster in order to provide workloads with one (or several) interface(s) to communicate with other workloads attached to the same network(s) at the link-layer. The main CNI Plugin interface in these pods remains intact, allowing the standard K8s functionalities to still be available for the pods (services, communications using the main interface, etc.).
The following figure outlines a high-level overview of L2S-M, with an illustrative example of a K8s cluster with L2S-M installed and running. L2S-M builds a programmable data plane using SDN switches over a K8s infrastructure. These switches can be either virtual (deployed by the L2S-M operator) or physical (such as those that can be found in a classic datacentre infrastructure).
![alt text](../assets/v1_architecture.png?raw=true)
**NOTE**: The current version of L2S-M utilizes an infrastructure of virtual switches based on [Open Virtual Switch (OVS)](http://www.openvswitch.org). This implementation can be followed up in https://github.com/Networks-it-uc3m/l2sm-switch .
In L2S-M, a k8s node deploys a virtual SDN switch or is connected to a physical SDN switch. Virtual switches are interconnected through point-to-point links. These links are established using IP tunnels (based on VXLAN technologies). This way, SDN switches build an overlay network that interconnects all the K8s nodes. L2S-M uses an SDN controller to install forwarding rules on the virtual/physical switches. This way, data traffic among workloads is appropriately distributed through isolated virtual networks (i.e., the SDN controller instructs the switches which ports should be used to forward and/or block incoming/outgoing traffic).
Specifically for K8s clusters, the element in charge of managing the creation, deletion and management of virtual networks is the L2S-M operator. This operator treats virtual networks as Multus CRDs, using the K8s events to detect the instances where a pod wants to attach/detach from a virtual network. In the former case, the operator will select one of the available interfaces in the SDN switch, and associate it with the virtual network that wants to be used. This interface will appear in the pod as a secondary interface that can be used to communicate with other pods attached to the network, which will be seen as if they were deployed in the same Local Area Network (LAN). The CNI interface remains intact.
To provide isolation among virtual networks, the operator interacts with the SDN controller component to communicate which ports are associated with each virtual network, updating its status every time a pod is deployed/deleted. Using this information, the SDN controller injects the corresponding rules in the switches, forwarding and/or blocking traffic according to the virtual networks being used at each moment.
**NOTE**: The current version of L2S-M utilizes a custom implementation of SDN controller. This sdn controller implementation can be seen at https://github.com/Networks-it-uc3m/l2sm-controller .
More information on how to use this solution can be seen in the [how to use guide](./general-use.md).
# General Use of L2S-M Application
This document will guide you through the usage of L2S-M, a tool designed to manage L2 networks, overlays, and Network Edge Devices (NEDs) within a Kubernetes cluster environment. L2S-M uses Custom Resource Definitions (CRDs) to enable flexible network management and pod attachment within Kubernetes.
For more specific examples, you can go to the [examples section](../examples/), this document is meant to be a general use guide.
## Custom Resource Definitions (CRDs)
L2S-M introduces three core CRDs that allow users to configure networks, overlays, and edge devices dynamically:
### 1. **L2Network CRD**
- **Purpose**: Defines a Layer 2 virtual network inside the Kubernetes environment.
- **Configurable Fields**:
- **Network Type**: Specifies the type of network.
- **Connectivity**: Controls the connection with the Software-Defined Networking (SDN) controller.
- **Connected Pods**: Lists the pods connected to this network.
- **Usage**: Once a network is defined, pods can be connected to it. The L2Network CRD provides specifications through the `spec` field, where the user defines the network attributes, while the `status` field reports the current state of the network, including the pods connected to it.
- An example of this CR can be found [here](../config/samples/l2sm_v1_l2network.yaml)
### 2. **Overlay CRD**
- **Purpose**: Defines the logical connections between nodes in the cluster, creating the overlay network.
- **Configurable Fields**:
- **Topology**: Specifies how nodes should be interconnected.
- **Switch Template**: Defines the type of switches used within the overlay.
- **Network Controller**: Identifies the SDN controller responsible for managing the topology.
- **Usage**: Administrators can use the Overlay CRD to define the connections between nodes based on their resource capacities or geographic location, creating custom topologies suited to specific needs.
- An example of this CR can be found [here](../config/samples/l2sm_v1_overlay.yaml)
### 3. **NetworkEdgeDevice (NED) CRD**
- **Purpose**: Extends the network beyond the cluster, enabling communication with external networks or other clusters.
- **Configurable Fields**:
- **Device Type**: Defines the hardware or software that forms the edge device.
- **Connections**: Specifies the external networks or clusters this NED should connect to.
- **Usage**: The NED CRD facilitates inter-cluster communication by connecting Kubernetes clusters or other platforms like OpenStack. Each NED is controlled by an SDN controller for dynamic flow control and traffic management.
- An example of this CR can be found [here](../config/samples/l2sm_v1_networkedgedevice.yaml)
## Attaching Pods to Networks
Pods can be dynamically attached to L2 networks defined by the L2Network CRD. This process involves the following steps:
1. **Defining the L2Network**: Use the L2Network CRD to create a network in Kubernetes. The network will be managed by the L2S-M controller, which communicates with the SDN controller to configure the necessary networking parameters.
2. **Scheduling Pods**: When a pod is deployed in the cluster, it can be attached to the L2Network by specifying the network during the pod creation process. The L2S-M controller will automatically configure the required network interfaces and assign IP addresses via the integrated IP Address Management (IPAM) system.
3. **Monitoring Connectivity**: Once attached, the status of the pod’s network connectivity can be checked via the L2Network CRD’s `status` field, which will list all connected pods and report any changes in the connectivity state.
# L2S-M Development
This component is essentially a set of Custom Resource Definitions (CRDs) accompanied by a controller and a manager. It's designed to manage the overlays and virtual networks that L2S-M uses between pods within a K8s cluster.
## Getting Started
### Prerequisites
- go version v1.21.0+
- docker version 17.03+.
- kubectl version v1.11.3+.
- Access to a Kubernetes v1.11.3+ cluster.
### To Deploy on the cluster
**Build and push your image to the location specified by `IMG`, inside the Makefile:**
```sh
make docker-build docker-push
```
**NOTE:** The image ought to be published in the personal registry you specified.
And it is required to have access to pull the image from the working environment.
Make sure you have the proper permission to the registry if the above commands don’t work.
**Deploy the Manager to the cluster with the image specified by `IMG`:**
```sh
make deploy
```
**Create instances of your solution**
You can apply the samples (examples) from the config/sample:
```sh
kubectl apply -k config/samples/
```
>**NOTE**: Ensure that the samples has default values to test it out.
### To Uninstall
**Delete the instances (CRs) from the cluster:**
```sh
kubectl delete -k config/samples/
```
**UnDeploy the controller from the cluster:**
```sh
make undeploy
```
> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin
privileges or be logged in as admin.
### To Run locally the solution and make your custom changes
If you are interested in running the solution locally, feel free to make your own branch and start developing! Any feedback is welcome as well.
We provide the following commands to run the application locally
1. **Install the CRDs into the cluster:**
```sh
make install
```
2. **Deploy the webhook server locally:**
```sh
make deploy-webhook
```
3. **Run the application with the changes:**
```sh
make run
```
And once you've finished:
**Delete the APIs(CRDs) from the cluster:**
```sh
make uninstall
```
**Remove the Webhook Server from the cluster:**
```sh
make undeploy-webhook
```
## Project Distribution
Following are the steps to build the installer and distribute this project to users.
1. Build the installer for the image built and published in the registry:
```sh
make build-installer
```
NOTE: The makefile target mentioned above generates an 'install.yaml'
file in the deployment directory. This file contains all the resources built
with Kustomize, which are necessary to install this project without
its dependencies.
2. Using the installer
Users can just run kubectl apply -f <URL for YAML BUNDLE> to install the project, i.e.:
```sh
kubectl apply -f https://raw.githubusercontent.com/<org>/L2S-M/<tag or branch>/deployments/l2sm-deployment.yaml
```
\ No newline at end of file
# L2S-M in a Inter-Cluster scenario
>**Note: Work in progress** :wrench::wrench:
> This feature and repository is under development, keep it in mind when testing the application. For a stable version, refer to the main branch in the [L2S-M official repository](https://github.com/Networks-it-uc3m/L2S-M).
## How it works
### Components in inter-cluster scenario:
<p align="center">
<img src="../assets/inter-cluster-arch.svg" width="600">
</p>
### Sequence Diagram
<p align="center">
<img src="../assets/inter-cluster-diagram.svg" width="600">
</p>
## YAML examples:
### Inter cluster network example:
```yaml
apiVersion: l2sm.k8s.local/v1
kind: L2SMNetwork
metadata:
name: spain-network
spec:
type: inter-vnet
config: |
{
"provider": {
"name": "uc3m",
"domain": "idco.uc3m.es"
},
"accessList": ["public-key-1", "public-key-2"]
}
signature: sxySO0jHw4h1kcqO/LMLDgOoOeH8dOn8vZWv4KMBq0upxz3lcbl+o/36JefpEwSlBJ6ukuKiQ79L4rsmmZgglk6y/VL54DFyLfPw9RJn3mzl99YE4qCaHyEBANSw+d5hPaJ/I8q+AMtjrYpglMTRPf0iMZQMNtMd0CdeX2V8aZOPCQP75PsZkWukPdoAK/++y1vbFQ6nQKagvpUZfr7Ecb4/QY+hIAzepm6N6lNiFNTgj6lGTrFK0qCVfRhMD+vXbBP6xzZjB2N1nIheK9vx7kvj3HORjZ+odVMa+AOU5ShSKpzXTvknrtcRTcWWmXPNUZLoq5k3U+z1g1OTFcjMdQ====
```
### Pod creation and attachment
```yaml
apiVersion: v1
kind: Secret
metadata:
name: spain-network-signature
type: Opaque
data:
public-key.pem: <signature-using-private-key-1>
```
```yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
annotations:
l2sm/networks: spain-network
spec:
containers:
- name: ping
image: busybox
volumes:
- name: inter-vnet-signature
secret:
secretName: spain-network-signature
```
// Copyright 2024 Universidad Carlos III de Madrid
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package v1 contains API Schema definitions for the l2sm v1 API group
// +kubebuilder:object:generate=true
// +groupName=l2sm.l2sm.k8s.local
package v1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "l2sm.l2sm.k8s.local", Version: "v1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
// Copyright 2024 Universidad Carlos III de Madrid
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
// NetworkType represents the type of network being configured.
// +kubebuilder:validation:Enum=ext-vnet;vnet;vlink
type NetworkType string
const (
NetworkTypeExtVnet NetworkType = "ext-vnet"
NetworkTypeVnet NetworkType = "vnet"
NetworkTypeVlink NetworkType = "vlink"
)
// +kubebuilder:validation:Enum=Available;Unavailable;Unknown
type ConnectivityStatus string
const (
OnlineStatus ConnectivityStatus = "Available"
OfflineStatus ConnectivityStatus = "Unavailable"
UnknownStatus ConnectivityStatus = "Unknown"
)
// ProviderSpec defines the provider's name and domain. This is used in the inter-cluster scenario, to allow managing of the network in the external environment by this certified SDN provider.
type ProviderSpec struct {
Name string `json:"name"`
Domain string `json:"domain"`
}
// L2NetworkSpec defines the desired state of L2Network
type L2NetworkSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// NetworkType represents the type of network being configured.
Type NetworkType `json:"type"`
// Config is an optional field that is meant to be used as additional configuration depending on the type of network. Check each type of network for specific configuration definitions.
Config *string `json:"config,omitempty"`
// Provider is an optional field representing a provider spec. Check the provider spec definition for more details
Provider *ProviderSpec `json:"provider,omitempty"`
}
// L2NetworkStatus defines the observed state of L2Network
type L2NetworkStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Existing Pods in the cluster, connected to the specific network
ConnectedPods []string `json:"connectedPods,omitempty"`
// Status of the connectivity to the internal SDN Controller. If there is no connection, internal l2sm-switches won't forward traffic
// +kubebuilder:default=Unavailable
InternalConnectivity *ConnectivityStatus `json:"internalConnectivity"`
// Status of the connectivity to the external provider SDN Controller. If there is no connectivity, the exisitng l2sm-ned in the cluster won't forward packages to the external clusters.
ProviderConnectivity *ConnectivityStatus `json:"providerConnectivity,omitempty"`
}
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="AVAILABILITY",type="string",JSONPath=".status.internalConnectivity",description="Internal SDN Controller Connectivity"
// +kubebuilder:printcolumn:name="CONNECTED_PODS",type=integer,JSONPath=".status.connectedPods",description="Internal SDN Controller Connectivity"
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
// L2Network is the Schema for the l2networks API
type L2Network struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec L2NetworkSpec `json:"spec,omitempty"`
Status L2NetworkStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// L2NetworkList contains a list of L2Network
type L2NetworkList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []L2Network `json:"items"`
}
func init() {
SchemeBuilder.Register(&L2Network{}, &L2NetworkList{})
}
// Copyright 2024 Universidad Carlos III de Madrid
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package v1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
// The SDN Controller that manages the overlay network.
type NetworkControllerSpec struct {
// Name of the Network controller
Name string `json:"name"`
// Domain where the controller can be reached at. Must be a valid IP Address or Domain name, reachable from all the nodes where the switches are deployed at.
Domain string `json:"domain"`
}
type NeighborSpec struct {
// Name of the cluster the link is going to be made upon.
Node string `json:"node"`
// Domain where the neighbor's NED switch can be reached at. Must be a valid IP Address or Domain name, reachable from the node the NED
// is going to be deployed at.
Domain string `json:"domain"`
}
type SwitchPodSpec struct {
// List of volumes that can be mounted by containers belonging to the pod.
// More info: https://kubernetes.io/docs/concepts/storage/volumes
// +optional
// +patchMergeKey=name
// +patchStrategy=merge,retainKeys
// +listType=map
// +listMapKey=name
Volumes []corev1.Volume `json:"volumes,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"`
// List of initialization containers belonging to the pod.
// Init containers are executed in order prior to containers being started. If any
// init container fails, the pod is considered to have failed and is handled according
// to its restartPolicy. The name for an init container or normal container must be
// unique among all containers.
// Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes.
// The resourceRequirements of an init container are taken into account during scheduling
// by finding the highest request/limit for each resource type, and then using the max of
// of that value or the sum of the normal containers. Limits are applied to init containers
// in a similar fashion.
// Init containers cannot currently be added or removed.
// Cannot be updated.
// More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
// +patchMergeKey=name
// +patchStrategy=merge
// +listType=map
// +listMapKey=name
InitContainers []corev1.Container `json:"initContainers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,20,rep,name=initContainers"`
// List of containers belonging to the pod.
// Containers cannot currently be added or removed.
// There must be at least one container in a Pod.
// Cannot be updated.
// +patchMergeKey=name
// +patchStrategy=merge
// +listType=map
// +listMapKey=name
Containers []corev1.Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=containers"`
// Host networking requested for this pod. Use the host's network namespace.
// If this option is set, the ports that will be used must be specified.
// Default to false.
// +k8s:conversion-gen=false
// +optional
HostNetwork bool `json:"hostNetwork,omitempty" protobuf:"varint,11,opt,name=hostNetwork"`
}
type SwitchTemplateSpec struct {
// Standard object's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`
// Specification of the desired behavior of the pod.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
// +optional
Spec SwitchPodSpec `json:"spec,omitempty"`
}
type NodeConfigSpec struct {
NodeName string `json:"nodeName"`
IPAddress string `json:"ipAddress"`
}
// NetworkEdgeDeviceSpec defines the desired state of NetworkEdgeDevice
type NetworkEdgeDeviceSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// The SDN Controller that manages the overlay network. Must specify a domain and a name.
NetworkController *NetworkControllerSpec `json:"networkController"`
// Node Configuration
NodeConfig *NodeConfigSpec `json:"nodeConfig"`
// Field exclusive to the multi-domain overlay type. If specified in other types of overlays, the reosurce will launch an error and won't be created.
Neighbors []NeighborSpec `json:"neighbors,omitempty"`
// Template describes the virtual switch pod that will be created.
SwitchTemplate *SwitchTemplateSpec `json:"switchTemplate"`
// Available pod range. The pod specified will run a local grpc server and the next one will be used for the VXLAN creation
}
// NetworkEdgeDeviceStatus defines the observed state of NetworkEdgeDevice
type NetworkEdgeDeviceStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Status of the overlay. Is available when switches are connected between them and with the network Controller.
// +kubebuilder:default=Unavailable
Availability *ConnectivityStatus `json:"availability"`
ConnectedNeighbors []NeighborSpec `json:"connectedNeighbors,omitempty"`
OpenflowId string `json:"openflowId,omitempty"`
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// NetworkEdgeDevice is the Schema for the networkedgedevices API
// +kubebuilder:printcolumn:name="STATUS",type="string",JSONPath=".status.availability",description="Availability status of the overlay"
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
type NetworkEdgeDevice struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec NetworkEdgeDeviceSpec `json:"spec,omitempty"`
Status NetworkEdgeDeviceStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// NetworkEdgeDeviceList contains a list of NetworkEdgeDevice
type NetworkEdgeDeviceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []NetworkEdgeDevice `json:"items"`
}
func init() {
SchemeBuilder.Register(&NetworkEdgeDevice{}, &NetworkEdgeDeviceList{})
}
// Copyright 2024 Universidad Carlos III de Madrid
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type Link struct {
EndpointA string `json:"endpointA"`
EndpointB string `json:"endpointB"`
}
type TopologySpec struct {
Nodes []string `json:"nodes"`
Links []Link `json:"links"`
}
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
// OverlaySpec defines the desired state of Overlay
type OverlaySpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// The SDN Controller that manages the overlay network. Must specify a domain and a name.
NetworkController *NetworkControllerSpec `json:"networkController"`
// Topology represents the desired topology, it's represented by the 'Nodes' field, a list of nodes where the switches are going to be deployed and a list of bidirectional links,
// selecting the nodes that are going to be linked.
Topology *TopologySpec `json:"topology,omitempty"`
// Field exclusive to the multi-domain overlay type. If specified in other types of overlays, the reosurce will launch an error and won't be created.
Neighbors []NeighborSpec `json:"neighbors,omitempty"`
// Template describes the virtual switch pod that will be created.
SwitchTemplate *SwitchTemplateSpec `json:"switchTemplate"`
}
// OverlayStatus defines the observed state of Overlay
type OverlayStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
ConnectedNeighbors []NeighborSpec `json:"connectedNeighbors,omitempty"`
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// Overlay is the Schema for the overlays API
type Overlay struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec OverlaySpec `json:"spec,omitempty"`
Status OverlayStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// OverlayList contains a list of Overlay
type OverlayList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Overlay `json:"items"`
}
func init() {
SchemeBuilder.Register(&Overlay{}, &OverlayList{})
}
//go:build !ignore_autogenerated
// Copyright 2024 Universidad Carlos III de Madrid
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Code generated by controller-gen. DO NOT EDIT.
package v1
import (
corev1 "k8s.io/api/core/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *L2Network) DeepCopyInto(out *L2Network) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new L2Network.
func (in *L2Network) DeepCopy() *L2Network {
if in == nil {
return nil
}
out := new(L2Network)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *L2Network) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *L2NetworkList) DeepCopyInto(out *L2NetworkList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]L2Network, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new L2NetworkList.
func (in *L2NetworkList) DeepCopy() *L2NetworkList {
if in == nil {
return nil
}
out := new(L2NetworkList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *L2NetworkList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *L2NetworkSpec) DeepCopyInto(out *L2NetworkSpec) {
*out = *in
if in.Config != nil {
in, out := &in.Config, &out.Config
*out = new(string)
**out = **in
}
if in.Provider != nil {
in, out := &in.Provider, &out.Provider
*out = new(ProviderSpec)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new L2NetworkSpec.
func (in *L2NetworkSpec) DeepCopy() *L2NetworkSpec {
if in == nil {
return nil
}
out := new(L2NetworkSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *L2NetworkStatus) DeepCopyInto(out *L2NetworkStatus) {
*out = *in
if in.ConnectedPods != nil {
in, out := &in.ConnectedPods, &out.ConnectedPods
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.InternalConnectivity != nil {
in, out := &in.InternalConnectivity, &out.InternalConnectivity
*out = new(ConnectivityStatus)
**out = **in
}
if in.ProviderConnectivity != nil {
in, out := &in.ProviderConnectivity, &out.ProviderConnectivity
*out = new(ConnectivityStatus)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new L2NetworkStatus.
func (in *L2NetworkStatus) DeepCopy() *L2NetworkStatus {
if in == nil {
return nil
}
out := new(L2NetworkStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Link) DeepCopyInto(out *Link) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Link.
func (in *Link) DeepCopy() *Link {
if in == nil {
return nil
}
out := new(Link)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NeighborSpec) DeepCopyInto(out *NeighborSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeighborSpec.
func (in *NeighborSpec) DeepCopy() *NeighborSpec {
if in == nil {
return nil
}
out := new(NeighborSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkControllerSpec) DeepCopyInto(out *NetworkControllerSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkControllerSpec.
func (in *NetworkControllerSpec) DeepCopy() *NetworkControllerSpec {
if in == nil {
return nil
}
out := new(NetworkControllerSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkEdgeDevice) DeepCopyInto(out *NetworkEdgeDevice) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkEdgeDevice.
func (in *NetworkEdgeDevice) DeepCopy() *NetworkEdgeDevice {
if in == nil {
return nil
}
out := new(NetworkEdgeDevice)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *NetworkEdgeDevice) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkEdgeDeviceList) DeepCopyInto(out *NetworkEdgeDeviceList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]NetworkEdgeDevice, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkEdgeDeviceList.
func (in *NetworkEdgeDeviceList) DeepCopy() *NetworkEdgeDeviceList {
if in == nil {
return nil
}
out := new(NetworkEdgeDeviceList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *NetworkEdgeDeviceList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkEdgeDeviceSpec) DeepCopyInto(out *NetworkEdgeDeviceSpec) {
*out = *in
if in.NetworkController != nil {
in, out := &in.NetworkController, &out.NetworkController
*out = new(NetworkControllerSpec)
**out = **in
}
if in.NodeConfig != nil {
in, out := &in.NodeConfig, &out.NodeConfig
*out = new(NodeConfigSpec)
**out = **in
}
if in.Neighbors != nil {
in, out := &in.Neighbors, &out.Neighbors
*out = make([]NeighborSpec, len(*in))
copy(*out, *in)
}
if in.SwitchTemplate != nil {
in, out := &in.SwitchTemplate, &out.SwitchTemplate
*out = new(SwitchTemplateSpec)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkEdgeDeviceSpec.
func (in *NetworkEdgeDeviceSpec) DeepCopy() *NetworkEdgeDeviceSpec {
if in == nil {
return nil
}
out := new(NetworkEdgeDeviceSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkEdgeDeviceStatus) DeepCopyInto(out *NetworkEdgeDeviceStatus) {
*out = *in
if in.Availability != nil {
in, out := &in.Availability, &out.Availability
*out = new(ConnectivityStatus)
**out = **in
}
if in.ConnectedNeighbors != nil {
in, out := &in.ConnectedNeighbors, &out.ConnectedNeighbors
*out = make([]NeighborSpec, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkEdgeDeviceStatus.
func (in *NetworkEdgeDeviceStatus) DeepCopy() *NetworkEdgeDeviceStatus {
if in == nil {
return nil
}
out := new(NetworkEdgeDeviceStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeConfigSpec) DeepCopyInto(out *NodeConfigSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeConfigSpec.
func (in *NodeConfigSpec) DeepCopy() *NodeConfigSpec {
if in == nil {
return nil
}
out := new(NodeConfigSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Overlay) DeepCopyInto(out *Overlay) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Overlay.
func (in *Overlay) DeepCopy() *Overlay {
if in == nil {
return nil
}
out := new(Overlay)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Overlay) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OverlayList) DeepCopyInto(out *OverlayList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Overlay, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverlayList.
func (in *OverlayList) DeepCopy() *OverlayList {
if in == nil {
return nil
}
out := new(OverlayList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *OverlayList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OverlaySpec) DeepCopyInto(out *OverlaySpec) {
*out = *in
if in.NetworkController != nil {
in, out := &in.NetworkController, &out.NetworkController
*out = new(NetworkControllerSpec)
**out = **in
}
if in.Topology != nil {
in, out := &in.Topology, &out.Topology
*out = new(TopologySpec)
(*in).DeepCopyInto(*out)
}
if in.Neighbors != nil {
in, out := &in.Neighbors, &out.Neighbors
*out = make([]NeighborSpec, len(*in))
copy(*out, *in)
}
if in.SwitchTemplate != nil {
in, out := &in.SwitchTemplate, &out.SwitchTemplate
*out = new(SwitchTemplateSpec)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverlaySpec.
func (in *OverlaySpec) DeepCopy() *OverlaySpec {
if in == nil {
return nil
}
out := new(OverlaySpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OverlayStatus) DeepCopyInto(out *OverlayStatus) {
*out = *in
if in.ConnectedNeighbors != nil {
in, out := &in.ConnectedNeighbors, &out.ConnectedNeighbors
*out = make([]NeighborSpec, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverlayStatus.
func (in *OverlayStatus) DeepCopy() *OverlayStatus {
if in == nil {
return nil
}
out := new(OverlayStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderSpec.
func (in *ProviderSpec) DeepCopy() *ProviderSpec {
if in == nil {
return nil
}
out := new(ProviderSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SwitchPodSpec) DeepCopyInto(out *SwitchPodSpec) {
*out = *in
if in.Volumes != nil {
in, out := &in.Volumes, &out.Volumes
*out = make([]corev1.Volume, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.InitContainers != nil {
in, out := &in.InitContainers, &out.InitContainers
*out = make([]corev1.Container, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Containers != nil {
in, out := &in.Containers, &out.Containers
*out = make([]corev1.Container, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SwitchPodSpec.
func (in *SwitchPodSpec) DeepCopy() *SwitchPodSpec {
if in == nil {
return nil
}
out := new(SwitchPodSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SwitchTemplateSpec) DeepCopyInto(out *SwitchTemplateSpec) {
*out = *in
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SwitchTemplateSpec.
func (in *SwitchTemplateSpec) DeepCopy() *SwitchTemplateSpec {
if in == nil {
return nil
}
out := new(SwitchTemplateSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TopologySpec) DeepCopyInto(out *TopologySpec) {
*out = *in
if in.Nodes != nil {
in, out := &in.Nodes, &out.Nodes
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Links != nil {
in, out := &in.Links, &out.Links
*out = make([]Link, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologySpec.
func (in *TopologySpec) DeepCopy() *TopologySpec {
if in == nil {
return nil
}
out := new(TopologySpec)
in.DeepCopyInto(out)
return out
}