Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ COPY go.sum go.sum
RUN go mod download

# Copy the go source
COPY cmd/main.go cmd/main.go
COPY cmd/func-operator/main.go cmd/func-operator/main.go
COPY api/ api/
COPY internal/ internal/

Expand All @@ -21,11 +21,11 @@ COPY internal/ internal/
# 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
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/func-operator/main.go

FROM builder AS builder-debug
# Build with debug symbols for delve
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -gcflags="all=-N -l" -o manager-debug cmd/main.go
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -gcflags="all=-N -l" -o manager-debug cmd/func-operator/main.go
# Install Delve
RUN go install github.com/go-delve/delve/cmd/dlv@latest

Expand Down
29 changes: 29 additions & 0 deletions Dockerfile.source-objectbucket
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Build the manager binary
FROM golang:1.26 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/objectbucket-notifications-adapter/main.go cmd/objectbucket-notifications-adapter/main.go
COPY api/ api/
COPY internal/ internal/

# Build
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/objectbucket-notifications-adapter/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"]
75 changes: 68 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)
# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both
# functions.dev/func-operator-bundle:$VERSION and functions.dev/func-operator-catalog:$VERSION.
IMAGE_TAG_BASE ?= localhost:5001/func-operator
IMAGE_TAG_BASE_SOURCE_OBJECTBUCKET ?= localhost:5001/objectbucket-notifications-adapter

DEBUG_IMAGE_TAG_BASE ?= $(IMAGE_TAG_BASE)-debug

Expand All @@ -56,6 +57,7 @@ endif
OPERATOR_SDK_VERSION ?= v1.41.1
# Image URL to use all building/pushing image targets
IMG ?= $(IMAGE_TAG_BASE):$(VERSION)
IMG_SOURCE_OBJECTBUCKET ?= $(IMAGE_TAG_BASE_SOURCE_OBJECTBUCKET):$(VERSION)
DEBUG_IMG ?= $(DEBUG_IMAGE_TAG_BASE):v$(VERSION)

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
Expand Down Expand Up @@ -116,7 +118,7 @@ vet: ## Run go vet against code.

.PHONY: test
test: manifests generate fmt vet setup-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
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v e2e) -coverprofile cover.out

.PHONY: test-e2e ## Run e2e tests.
test-e2e: ginkgo
Expand Down Expand Up @@ -145,12 +147,23 @@ lint-config: golangci-lint ## Verify golangci-lint linter configuration
##@ Build

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
go build -o bin/manager cmd/main.go
build: manifests generate fmt vet ## Build func-operator manager binary.
go build -o bin/manager cmd/func-operator/main.go

.PHONY: build-source-objectbucket
build-source-objectbucket: manifests generate fmt vet ## Build objectbucket-notifications-adapter binary.
go build -o bin/source-objectbucket cmd/objectbucket-notifications-adapter/main.go

.PHONY: build-sources
build-sources: build-source-objectbucket ## Build all event source binaries.

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./cmd/main.go
run: manifests generate fmt vet ## Run the func-operator controller from your host.
go run ./cmd/func-operator/main.go

.PHONY: run-source-objectbucket
run-source-objectbucket: manifests generate fmt vet ## Run the objectbucket-notifications-adapter controller from your host.
go run ./cmd/objectbucket-notifications-adapter/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.
Expand Down Expand Up @@ -178,6 +191,20 @@ docker-push-debugger: ## Push debugger docker image with the manager.
# - 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-build-source-objectbucket
docker-build-source-objectbucket: ## Build docker image for the objectbucket-notifications-adapter.
$(CONTAINER_TOOL) build -t ${IMG_SOURCE_OBJECTBUCKET} -f Dockerfile.source-objectbucket .

.PHONY: docker-push-source-objectbucket
docker-push-source-objectbucket: ## Push docker image for the objectbucket-notifications-adapter.
$(CONTAINER_TOOL) push ${IMG_SOURCE_OBJECTBUCKET}

.PHONY: docker-build-sources
docker-build-sources: docker-build-source-objectbucket ## Build docker images for all event sources.

.PHONY: docker-push-sources
docker-push-sources: docker-push-source-objectbucket ## Push docker images for all event sources.

.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
Expand Down Expand Up @@ -239,12 +266,31 @@ patch-registry-cert: ## Patch deployment to mount local registry certificate (fo
fi

.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
deploy: manifests kustomize ## Deploy func-operator 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 -
$(MAKE) patch-registry-cert
$(KUBECTL) wait deployment --all --timeout=120s --for=condition=Available -n func-operator-system

.PHONY: deploy-source-objectbucket
deploy-source-objectbucket: manifests kustomize ## Deploy objectbucket-notifications-adapter to the K8s cluster.
cd config/sources/objectbucket/manager && $(KUSTOMIZE) edit set image controller=${IMG_SOURCE_OBJECTBUCKET}
$(KUSTOMIZE) build config/sources/objectbucket/default | $(KUBECTL) apply -f -
$(KUBECTL) wait deployment --all --timeout=120s --for=condition=Available -n objectbucket-notifications-adapter-system

.PHONY: deploy-source-objectbucket-kafka
deploy-source-objectbucket-kafka: manifests kustomize ## Deploy objectbucket-notifications-adapter in Kafka mode.
cd config/sources/objectbucket/manager && $(KUSTOMIZE) edit set image controller=${IMG_SOURCE_OBJECTBUCKET}
$(KUSTOMIZE) build config/sources/objectbucket/kafka | $(KUBECTL) apply -f -
$(KUBECTL) wait deployment --all --timeout=120s --for=condition=Available -n objectbucket-notifications-adapter-system

.PHONY: deploy-combined
deploy-combined: manifests kustomize ## Deploy both func-operator and all event sources in a single namespace.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
cd config/sources/objectbucket/manager && $(KUSTOMIZE) edit set image controller=${IMG_SOURCE_OBJECTBUCKET}
$(KUSTOMIZE) build config/combined | $(KUBECTL) apply -f -
$(KUBECTL) wait deployment --all --timeout=120s --for=condition=Available -n func-operator-system

.PHONY: deploy-debugger
deploy-debugger: manifests kustomize ## Deploy debug controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${DEBUG_IMG}
Expand All @@ -253,9 +299,17 @@ deploy-debugger: manifests kustomize ## Deploy debug controller to the K8s clust
$(MAKE) patch-registry-cert

.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.
undeploy: kustomize ## Undeploy func-operator controller from the K8s cluster. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

.PHONY: undeploy-source-objectbucket
undeploy-source-objectbucket: kustomize ## Undeploy objectbucket-notifications-adapter from the K8s cluster.
$(KUSTOMIZE) build config/sources/objectbucket/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

.PHONY: undeploy-combined
undeploy-combined: kustomize ## Undeploy both func-operator and all event sources from the K8s cluster.
$(KUSTOMIZE) build config/combined | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

.PHONY: create-kind-cluster
create-kind-cluster:
./hack/create-kind-cluster.sh
Expand Down Expand Up @@ -382,6 +436,13 @@ bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metada
$(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS)
$(OPERATOR_SDK) bundle validate ./bundle

.PHONY: bundle-combined
bundle-combined: manifests kustomize operator-sdk ## Generate combined OLM bundle with both func-operator and all event sources.
cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
cd config/sources/objectbucket/manager && $(KUSTOMIZE) edit set image controller=$(IMG_SOURCE_OBJECTBUCKET)
$(KUSTOMIZE) build config/combined/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS)
$(OPERATOR_SDK) bundle validate ./bundle

.PHONY: bundle-build
bundle-build: ## Build the bundle image.
$(CONTAINER_TOOL) build -f bundle.Dockerfile -t $(BUNDLE_IMG) .
Expand Down
9 changes: 9 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,13 @@ resources:
kind: Function
path: github.com/functions-dev/func-operator/api/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: functions.dev
group: sources
kind: ObjectBucketSource
path: github.com/functions-dev/func-operator/api/sources/v1alpha1
version: v1alpha1
version: "3"
48 changes: 48 additions & 0 deletions api/sources/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright 2026.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package v1alpha1 contains API Schema definitions for the sources v1alpha1 API group.
// +kubebuilder:object:generate=true
// +groupName=sources.functions.dev
package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)

var (
// GroupVersion is group version used to register these objects.
GroupVersion = schema.GroupVersion{Group: "sources.functions.dev", Version: "v1alpha1"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)

func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(GroupVersion,
&ObjectBucketSource{},
&ObjectBucketSourceList{},
)

metav1.AddToGroupVersion(scheme, GroupVersion)

return nil
}
79 changes: 79 additions & 0 deletions api/sources/v1alpha1/objectbucketsource_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
Copyright 2026.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
ConditionOBCCredentialsAvailable = "OBCCredentialsAvailable"
ConditionBucketNotificationSet = "BucketNotificationSet"
ConditionTestEventReceived = "TestEventReceived"

FinalizerName = "sources.functions.dev/objectbucketsource"
)

// ObjectBucketSourceSpec defines the desired state of ObjectBucketSource.
type ObjectBucketSourceSpec struct {
// ObjectBucketClaim is a reference to the ObjectBucketClaim in the same namespace.
ObjectBucketClaim OBCReference `json:"objectBucketClaim"`
// Events is the list of S3 event types to subscribe to (e.g. "s3:ObjectCreated:*").
Events []string `json:"events"`
// Sink is the endpoint to dispatch matching CloudEvents to.
Sink SinkSpec `json:"sink"`
}

type OBCReference struct {
// Name of the ObjectBucketClaim in the same namespace.
Name string `json:"name"`
}

// SinkSpec defines the destination for CloudEvents. URI can be an HTTP URL
// (e.g. "http://foo.bar.svc.cluster.local") or a Kafka topic reference
// (e.g. "kafka:my-topic").
type SinkSpec struct {
// URI is the destination to send CloudEvents to. Use an HTTP URL for
// HTTP delivery, or "kafka:<topic>" for Kafka delivery.
URI string `json:"uri"`
}

// ObjectBucketSourceStatus defines the observed state of ObjectBucketSource.
type ObjectBucketSourceStatus struct {
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// ObjectBucketSource is the Schema for the objectbucketsources API.
type ObjectBucketSource struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec ObjectBucketSourceSpec `json:"spec,omitempty"`
Status ObjectBucketSourceStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// ObjectBucketSourceList contains a list of ObjectBucketSource.
type ObjectBucketSourceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ObjectBucketSource `json:"items"`
}
Loading
Loading