# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2020-2025 Intel Corporation

# Default k8s command-line tool exec
export CLI_EXEC?=oc
# Container format for podman. Required to build containers with "ManifestType": "application/vnd.oci.image.manifest.v2+json",
export BUILDAH_FORMAT=docker
# Current Operator version
VERSION ?= 2.11.0
# Supported channels
CHANNELS ?= stable
# Default channel
DEFAULT_CHANNEL ?= stable

# Operator image registry
IMAGE_REGISTRY ?= registry.connect.redhat.com/intel
BUILD_REGISTRY ?= localhost
CONTAINER_TOOL ?= podman

FUZZ_TIME?=10m

# Add suffix directly to IMAGE_REGISTRY to enable empty registry(local images)
ifneq ($(and $(strip $(IMAGE_REGISTRY)), $(filter-out %/, $(IMAGE_REGISTRY))),)
override IMAGE_REGISTRY:=$(addsuffix /,$(IMAGE_REGISTRY))
endif
# tls verify flag for pushing images
TLS_VERIFY ?= false

REQUIRED_OPERATOR_SDK_VERSION ?= v1.25.2

IMAGE_TAG_BASE ?= $(IMAGE_REGISTRY)sriov-fec
BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION)

# Options for 'image-bundle'
ifneq ($(origin CHANNELS), undefined)
BUNDLE_CHANNELS := --channels=$(CHANNELS)
endif
ifneq ($(origin DEFAULT_CHANNEL), undefined)
BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL)
endif
BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)

IMG_VERSION := v$(VERSION)

OS = $(shell go env GOOS)
ARCH = $(shell go env GOARCH)

# Images URLs to use for all building/pushing image targets
export SRIOV_FEC_OPERATOR_IMAGE ?= $(IMAGE_REGISTRY)sriov-fec-operator:$(IMG_VERSION)
export SRIOV_FEC_DAEMON_IMAGE ?= $(IMAGE_REGISTRY)sriov-fec-daemon:$(IMG_VERSION)
export SRIOV_FEC_LABELER_IMAGE ?= $(IMAGE_REGISTRY)n3000-labeler:$(IMG_VERSION)

ifeq ($(CONTAINER_TOOL),podman)
 export SRIOV_FEC_NETWORK_DEVICE_PLUGIN_IMAGE ?= registry.redhat.io/openshift4/ose-sriov-network-device-plugin:v4.14
 export KUBE_RBAC_PROXY_IMAGE ?= registry.redhat.io/openshift4/ose-kube-rbac-proxy:v4.14
else
 export SRIOV_FEC_NETWORK_DEVICE_PLUGIN_IMAGE ?= ghcr.io/k8snetworkplumbingwg/sriov-network-device-plugin:v3.7.0
 export KUBE_RBAC_PROXY_IMAGE ?= gcr.io/kubebuilder/kube-rbac-proxy:v0.15.0
endif

CONTROLLER_TOOLS_VERSION ?= v0.14.0
ENVTEST_K8S_VERSION ?= 1.24
KUSTOMIZE_VERSION ?= 4.5.7
OPM_VERSION ?= 1.26.2
KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"

LOCALBIN ?= $(shell pwd)/bin$(REQUIRED_OPERATOR_SDK_VERSION)
## Tool Binaries
OPM ?= $(LOCALBIN)/opm
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest

# 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

# Setting SHELL to bash allows bash commands to be executed by recipes.
# This is a requirement for 'setup-envtest.sh' in the test target.
# 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

.PHONY: all
all: manager daemon labeler

$(LOCALBIN):
	mkdir -p $(LOCALBIN)

.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
	test -s $(LOCALBIN)/kustomize || { curl -s $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); }


.PHONY: opm
opm: $(OPM) ## Download opm locally if necessary.
$(OPM): $(LOCALBIN)
	test -s $(LOCALBIN)/opm || curl https://github.com/operator-framework/operator-registry/releases/download/v$(OPM_VERSION)/linux-amd64-opm -Lo $(LOCALBIN)/opm && chmod +x $(LOCALBIN)/opm

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
	test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)

.PHONY: envtest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
	test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest

.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
	KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" SRIOV_FEC_NAMESPACE=default go test ./... -coverprofile cover.out

TEST_PACKAGES := $(shell find . -name "*_test.go")

.PHONY: fuzz
fuzz:
	@for pkg in ${TEST_PACKAGES} ; do            \
		for target in `grep -oh -EI 'Fuzz([A-Z][a-z]*)+' $$pkg` ; do     \
			echo "Executing $$pkg#$$target";     \
			KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" SRIOV_FEC_NAMESPACE=default go test -fuzz=$$target $$pkg/.. -fuzztime=${FUZZ_TIME} || true; \
		done                              \
	done

# Build manager binary
.PHONY: manager
manager: generate fmt vet
	go build -race -o bin/manager main.go

#Build daemon binary
.PHONY: daemon
daemon: generate fmt vet
	go build -race -o bin/daemon cmd/daemon/main.go

#Build labeler binary
.PHONY: labeler
labeler: generate fmt vet
	go build -race -o bin/labeler cmd/labeler/main.go

# Run against the configured Kubernetes cluster in ~/.kube/config
.PHONY: run
run: generate fmt vet manifests
	go run ./main.go

##@ Deployment

ifndef ignore-not-found
  ignore-not-found = false
endif

# Install CRDs into a cluster
.PHONY: install
install: manifests kustomize
	$(KUSTOMIZE) build config/crd | $(CLI_EXEC) apply -f -

# Uninstall CRDs from a cluster
.PHONY: uninstall
uninstall: manifests kustomize
	$(KUSTOMIZE) build config/crd | $(CLI_EXEC) delete --ignore-not-found=$(ignore-not-found) -f -

# Deploy controller in the configured Kubernetes cluster in ~/.kube/config
.PHONY: deploy
deploy: manifests kustomize
	cd config/manager && $(KUSTOMIZE) edit set image sriov-fec-operator=$(SRIOV_FEC_OPERATOR_IMAGE)
	$(KUSTOMIZE) build config/default | envsubst | $(CLI_EXEC) apply -f -

# Generate manifests e.g. CRD, RBAC etc.
.PHONY: manifests
manifests: controller-gen
	$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
	FOLDER=. COPYRIGHT_FILE=COPYRIGHT ./copyright.sh

# Run go fmt against code
.PHONY: fmt
fmt:
	go fmt ./...

# Run go vet against code
.PHONY: vet
vet:
	go vet ./...

# Generate code
.PHONY: generate
generate: controller-gen
	$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."

# Build/Push daemon image
.PHONY: image-sriov-fec-daemon
image-sriov-fec-daemon:
	cp LICENSE TEMP_LICENSE_COPY
	$(CONTAINER_TOOL) build . -f Dockerfile.daemon -t $(SRIOV_FEC_DAEMON_IMAGE) --build-arg=VERSION=$(IMG_VERSION) --no-cache
	
.PHONY: podman-push-sriov-fec-daemon
podman-push-sriov-fec-daemon:
	podman push $(SRIOV_FEC_DAEMON_IMAGE) --tls-verify=$(TLS_VERIFY)

.PHONY: docker-push-sriov-fec-daemon
docker-push-sriov-fec-daemon:
	docker push $(SRIOV_FEC_DAEMON_IMAGE)

# Build/Push labeler image
.PHONY: image-sriov-fec-labeler
image-sriov-fec-labeler:
	cp LICENSE TEMP_LICENSE_COPY
	$(CONTAINER_TOOL) build . -f Dockerfile.labeler -t ${SRIOV_FEC_LABELER_IMAGE} --build-arg=VERSION=$(IMG_VERSION) --no-cache

.PHONY: podman-push-sriov-fec-labeler
podman-push-sriov-fec-labeler:
	podman push ${SRIOV_FEC_LABELER_IMAGE} --tls-verify=$(TLS_VERIFY)

.PHONY: docker-push-sriov-fec-labeler
docker-push-sriov-fec-labeler:
	docker push ${SRIOV_FEC_LABELER_IMAGE}

# Build/Push operator image
.PHONY: image-sriov-fec-operator
image-sriov-fec-operator:
	cp LICENSE TEMP_LICENSE_COPY
	$(CONTAINER_TOOL) build . -t $(SRIOV_FEC_OPERATOR_IMAGE) --build-arg=VERSION=$(IMG_VERSION) --no-cache

.PHONY: podman-push-sriov-fec-operator
podman-push-sriov-fec-operator:
	podman push $(SRIOV_FEC_OPERATOR_IMAGE) --tls-verify=$(TLS_VERIFY)

.PHONY: docker-push-sriov-fec-operator
docker-push-sriov-fec-operator:
	docker push $(SRIOV_FEC_OPERATOR_IMAGE)

# Build all the images
.PHONY: image
image: image-sriov-fec-daemon image-sriov-fec-labeler image-sriov-fec-operator image-bundle


# Retag all the images
.PHONY: retag
retag:
	$(CONTAINER_TOOL) tag $(BUILD_REGISTRY)/sriov-fec-daemon:$(IMG_VERSION) $(IMAGE_REGISTRY)sriov-fec-daemon:$(IMG_VERSION)
	$(CONTAINER_TOOL) tag $(BUILD_REGISTRY)/sriov-fec-labeler:$(IMG_VERSION) $(IMAGE_REGISTRY)sriov-fec-labeler:$(IMG_VERSION)
	$(CONTAINER_TOOL) tag $(BUILD_REGISTRY)/sriov-fec-operator:$(IMG_VERSION) $(IMAGE_REGISTRY)sriov-fec-operator:$(IMG_VERSION)
	$(CONTAINER_TOOL) tag $(BUILD_REGISTRY)/sriov-fec-bundle:$(IMG_VERSION) $(IMAGE_REGISTRY)sriov-fec-bundle:$(IMG_VERSION)
	$(CONTAINER_TOOL) tag $(BUILD_REGISTRY)/sriov-fec-index:$(VERSION) $(IMAGE_REGISTRY)sriov-fec-index:$(VERSION)

# Push all the images
.PHONY: push
push: $(CONTAINER_TOOL)-push-sriov-fec-daemon $(CONTAINER_TOOL)-push-sriov-fec-labeler $(CONTAINER_TOOL)-push-sriov-fec-operator $(CONTAINER_TOOL)-push-bundle

# Generate bundle manifests and metadata, then validate generated files.
.PHONY: bundle
bundle: check-operator-sdk-version manifests kustomize
	operator-sdk generate kustomize manifests -q
	cd config/manager && $(KUSTOMIZE) edit set image sriov-fec-operator=$(SRIOV_FEC_OPERATOR_IMAGE)
	$(KUSTOMIZE) build config/manifests | envsubst | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
	operator-sdk bundle validate ./bundle
	FOLDER=. COPYRIGHT_FILE=COPYRIGHT ./copyright.sh
	cat COPYRIGHT bundle.Dockerfile >bundle.tmp
	printf "\nLABEL com.redhat.openshift.versions=\"v4.10\"\n" >> bundle.tmp
	printf "\nCOPY TEMP_LICENSE_COPY /licenses/LICENSE\n" >> bundle.tmp
	mv bundle.tmp bundle.Dockerfile

# Build/Push the bundle image.
.PHONY: image-bundle
image-bundle: bundle
	cp LICENSE TEMP_LICENSE_COPY
	$(CONTAINER_TOOL) build -f bundle.Dockerfile -t $(BUNDLE_IMG) .

.PHONY: podman-push-bundle
podman-push-bundle:
	podman push $(BUNDLE_IMG) --tls-verify=$(TLS_VERIFY)
	
.PHONY: docker-push-bundle
docker-push-bundle:
	docker push $(BUNDLE_IMG)
.PHONY: build
build: image push

.PHONY: build_all
build_all: build
	$(MAKE) VERSION=$(VERSION) IMAGE_REGISTRY=$(IMAGE_REGISTRY) TLS_VERIFY=$(TLS_VERIFY) build_index

.PHONY: build_index
build_index: opm
	rm -fr sriov-fec-index
	mkdir sriov-fec-index
	$(OPM) init sriov-fec --default-channel=stable --output yaml > sriov-fec-index/index.yaml
ifeq ($(TLS_VERIFY), false)
	$(OPM) render $(BUNDLE_IMG) --output=yaml --skip-tls-verify >> sriov-fec-index/index.yaml
else
	$(OPM) render $(BUNDLE_IMG) --output=yaml >> sriov-fec-index/index.yaml
endif
	echo -e "---\nschema: olm.channel\npackage: sriov-fec\nname: stable\nentries:\n- name: sriov-fec.v$(VERSION)" >> sriov-fec-index/index.yaml
	$(OPM) validate sriov-fec-index
	$(CONTAINER_TOOL) build . -f Dockerfile.sriov-fec-index -t localhost/sriov-fec-index:$(VERSION) --no-cache
	$(MAKE) VERSION=$(VERSION) IMAGE_REGISTRY=$(IMAGE_REGISTRY) TLS_VERIFY=$(TLS_VERIFY) $(CONTAINER_TOOL)_push_index

.PHONY: podman_push_index
podman_push_index:
	podman push localhost/sriov-fec-index:$(VERSION) $(IMAGE_REGISTRY)sriov-fec-index:$(VERSION) --tls-verify=$(TLS_VERIFY)

.PHONY: docker_push_index
docker_push_index:
	docker tag localhost/sriov-fec-index:$(VERSION) $(IMAGE_REGISTRY)sriov-fec-index:$(VERSION)
	docker push $(IMAGE_REGISTRY)sriov-fec-index:$(VERSION)

.PHONY: install_operator_sdk
install_operator_sdk:
	curl -LO https://github.com/operator-framework/operator-sdk/releases/download/$(REQUIRED_OPERATOR_SDK_VERSION)/operator-sdk_linux_amd64
	chmod +x operator-sdk_linux_amd64 && sudo mv operator-sdk_linux_amd64 /usr/bin/operator-sdk

OPERATOR_SDK_INSTALLED := $(shell command -v operator-sdk version 2> /dev/null)
.PHONY: check-operator-sdk-version
check-operator-sdk-version:
ifndef OPERATOR_SDK_INSTALLED
	$(info operator-sdk is not installed - downloading it)
	$(MAKE) REQUIRED_OPERATOR_SDK_VERSION=$(REQUIRED_OPERATOR_SDK_VERSION) install_operator_sdk
else
ifneq ($(shell operator-sdk version | awk -F',' '{print $$1}' | awk -F'[""]' '{print $$2}'), $(REQUIRED_OPERATOR_SDK_VERSION))
	$(info updating operator-sdk to $(REQUIRED_OPERATOR_SDK_VERSION))
	$(MAKE) REQUIRED_OPERATOR_SDK_VERSION=$(REQUIRED_OPERATOR_SDK_VERSION) install_operator_sdk
endif
endif