From 59643cfc32b14c8b7d0e58abfdc41b6529b86d1d Mon Sep 17 00:00:00 2001 From: Dinesh Jilagam Date: Thu, 10 Sep 2026 20:36:41 +0530 Subject: [PATCH] Use OCR for FDK and FnServer images instead of DockerHub Propagate image pull and server startup failures --- Makefile | 8 ++++---- README.md | 3 --- commands/start.go | 8 +++++--- common/common.go | 31 ++++++++++++++----------------- common/image_stamp_test.go | 19 ++++++++++--------- config/config.go | 3 +++ langs/base.go | 2 +- langs/dotnet.go | 6 ++++-- langs/go.go | 6 ++++-- langs/java.go | 18 ++++++++++-------- langs/kotlin.go | 6 ++++-- langs/node.go | 6 ++++-- langs/python.go | 6 ++++-- langs/ruby.go | 6 ++++-- langs/runtime_support_test.go | 30 +++++++++++++++++------------- test/cli_docker_runtime_test.go | 6 +++--- test/cli_misc_test.go | 7 ++++--- 17 files changed, 95 insertions(+), 76 deletions(-) diff --git a/Makefile b/Makefile index 5185503e..5ece9bb1 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ all: dep build ./fn -build: +build: go build -o fn generate-oci-parity: @@ -11,7 +11,7 @@ generate-oci-parity: install: go build -o ${GOPATH}/bin/fn -docker: +docker: docker build -t fnproject/fn:latest . dep: @@ -24,7 +24,7 @@ release: GOOS=linux go build -o fn_linux GOOS=darwin go build -o fn_mac GOOS=windows go build -o fn.exe - # Uses fnproject/go:x.x-dev because golang:alpine has this issue: https://github.com/docker-library/golang/issues/155 and this https://github.com/docker-library/golang/issues/153 - docker run --rm -v ${PWD}:/go/src/github.com/fnproject/cli -w /go/src/github.com/fnproject/cli fnproject/go:1.23-dev go build -o fn_alpine + # Uses container-registry.oracle.com/oci_functions/go:x.x-dev because golang:alpine has this issue: https://github.com/docker-library/golang/issues/155 and this https://github.com/docker-library/golang/issues/153 + docker run --rm -v ${PWD}:/go/src/github.com/fnproject/cli -w /go/src/github.com/fnproject/cli container-registry.oracle.com/oci_functions/go:1.23-dev go build -o fn_alpine .PHONY: install test build diff --git a/README.md b/README.md index ce3e4e77..e4456f94 100644 --- a/README.md +++ b/README.md @@ -289,6 +289,3 @@ You can add more ignore rules by creating a `.fnignore` file in the watched dire ### Build from source See [CONTRIBUTING](https://github.com/fnproject/cli/blob/master/CONTRIBUTING.md) for instructions to build the CLI from source. - - - diff --git a/commands/start.go b/commands/start.go index 879ad881..2462d923 100644 --- a/commands/start.go +++ b/commands/start.go @@ -53,7 +53,7 @@ func StartCommand() cli.Command { }, cli.StringFlag{ Name: "version", - Usage: "Specify a specific fnproject/fnserver version to run, ex: '1.2.3'.", + Usage: "Specify a specific Fn server version to run, ex: '1.2.3'.", Value: "latest", }, cli.IntFlag{ @@ -143,7 +143,7 @@ func start(c *cli.Context) error { cmd.Stderr = os.Stderr err := cmd.Start() if err != nil { - log.Fatalln("Starting command failed:", err) + return fmt.Errorf("could not start Fn server image %s: %w", image, err) } done := make(chan error, 1) @@ -153,6 +153,7 @@ func start(c *cli.Context) error { // catch ctrl-c and kill sigC := make(chan os.Signal, 2) signal.Notify(sigC, os.Interrupt, syscall.SIGTERM) + defer signal.Stop(sigC) log.Println("¡¡¡ 'fn start' should NOT be used for PRODUCTION !!! see https://github.com/fnproject/fn-helm/") @@ -167,8 +168,9 @@ func start(c *cli.Context) error { } case err := <-done: if err != nil { - log.Println("Error: processed finished with error", err) + return fmt.Errorf("could not run Fn server image %s: %w", image, err) } + return nil } return err } diff --git a/common/common.go b/common/common.go index 8ffbcc6e..716dd1c7 100644 --- a/common/common.go +++ b/common/common.go @@ -54,7 +54,7 @@ import ( // Global docker variables. const ( - FunctionsDockerImage = "fnproject/fnserver" + FunctionsDockerImage = config.OCRImagePrefix + "fnserver" FuncfileDockerRuntime = "docker" MinRequiredDockerVersion = "17.5.0" BuildxBuilderInstance = "oci_fn_builder" @@ -1262,30 +1262,27 @@ func PullImage(image string) error { cmd := ShellCommander(containerEngineType, args...) cmd.SetStdOut(os.Stdout) cmd.SetStdErr(os.Stderr) - err = cmd.Start() - if err != nil { - log.Fatalln("Starting command failed:", err) - } - done := make(chan error, 1) - go func() { - done <- cmd.Wait() - }() - // catch ctrl-c and kill + // Register before starting so cancellation cannot miss a running pull. sigC := make(chan os.Signal, 2) signal.Notify(sigC, os.Interrupt, syscall.SIGTERM) + defer signal.Stop(sigC) + if err := cmd.Start(); err != nil { + return fmt.Errorf("could not start %s pull for %s: %w", containerEngineType, image, err) + } + + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() select { case <-sigC: - log.Println("Interrupt caught, exiting") - err = cmd.Kill() - if err != nil { - log.Println("Error: could not kill process") + if err := cmd.Kill(); err != nil { + return fmt.Errorf("could not cancel pull for %s: %w", image, err) } + <-done + return fmt.Errorf("pull cancelled for %s", image) case err := <-done: if err != nil { - log.Println("Processed finished with error:", err) - } else { - log.Println("Process finished gracefully") + return fmt.Errorf("%s pull failed for %s: %w", containerEngineType, image, err) } } return nil diff --git a/common/image_stamp_test.go b/common/image_stamp_test.go index 02a723b3..cdd47bba 100644 --- a/common/image_stamp_test.go +++ b/common/image_stamp_test.go @@ -1,6 +1,7 @@ package common import ( + "github.com/fnproject/cli/config" "path/filepath" "testing" ) @@ -17,26 +18,26 @@ func TestImageStampFuncFileV20180708UsesExpectedRuntimeVersion(t *testing.T) { { name: "legacy node runtime uses fallback version", runtime: "node", - wantBuild: "fnproject/node:22-dev", - wantRun: "fnproject/node:22", + wantBuild: config.OCRImagePrefix + "node:22-dev", + wantRun: config.OCRImagePrefix + "node:22", }, { name: "explicit node24 runtime keeps requested version", runtime: "node24", - wantBuild: "fnproject/node:24-dev", - wantRun: "fnproject/node:24", + wantBuild: config.OCRImagePrefix + "node:24-dev", + wantRun: config.OCRImagePrefix + "node:24", }, { name: "legacy java runtime uses fallback version", runtime: "java", - wantBuild: "fnproject/fn-java-fdk-build:jdk17-1.2.3", - wantRun: "fnproject/fn-java-fdk:jre17-1.2.3", + wantBuild: config.OCRImagePrefix + "fn-java-fdk-build:jdk17-1.2.3", + wantRun: config.OCRImagePrefix + "fn-java-fdk:jre17-1.2.3", }, { name: "explicit java21 runtime keeps requested version", runtime: "java21", - wantBuild: "fnproject/fn-java-fdk-build:jdk21-1.2.3", - wantRun: "fnproject/fn-java-fdk:jre21-1.2.3", + wantBuild: config.OCRImagePrefix + "fn-java-fdk-build:jdk21-1.2.3", + wantRun: config.OCRImagePrefix + "fn-java-fdk:jre21-1.2.3", }, } @@ -58,4 +59,4 @@ func TestImageStampFuncFileV20180708UsesExpectedRuntimeVersion(t *testing.T) { } }) } -} \ No newline at end of file +} diff --git a/config/config.go b/config/config.go index 2e208640..116675d9 100644 --- a/config/config.go +++ b/config/config.go @@ -32,6 +32,9 @@ import ( ) const ( + // OCRImagePrefix is the namespace, including the trailing slash, for Fn-provided images. + OCRImagePrefix = "container-registry.oracle.com/oci_functions/" + rootConfigPathName = ".fn" contextsPathName = "contexts" diff --git a/langs/base.go b/langs/base.go index b4748f37..0c673a91 100644 --- a/langs/base.go +++ b/langs/base.go @@ -104,7 +104,7 @@ type LangHelper interface { Extensions() []string // Runtime that will be used for the build (includes version) Runtime() string - // BuildFromImage is the base image to build off, typically fnproject/LANG:dev + // BuildFromImage is the base image to build off, from the OCR oci_functions namespace BuildFromImage() (string, error) // RunFromImage is the base image to use for deployment (usually smaller than the build images) RunFromImage() (string, error) diff --git a/langs/dotnet.go b/langs/dotnet.go index 79e55b5d..f5b811ed 100644 --- a/langs/dotnet.go +++ b/langs/dotnet.go @@ -22,6 +22,8 @@ import ( "io/ioutil" "os" "path/filepath" + + "github.com/fnproject/cli/config" ) var dotnetToFrameworkVersionMap = map[string]string{ @@ -56,12 +58,12 @@ func (lh *DotnetLangHelper) Extensions() []string { func (lh *DotnetLangHelper) BuildFromImage() (string, error) { fdkVersion, _ := lh.GetLatestFDKVersion() - return fmt.Sprintf("fnproject/dotnet:%s-%s-dev", lh.Version, fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"dotnet:%s-%s-dev", lh.Version, fdkVersion), nil } func (lh *DotnetLangHelper) RunFromImage() (string, error) { fdkVersion, _ := lh.GetLatestFDKVersion() - return fmt.Sprintf("fnproject/dotnet:%s-%s", lh.Version, fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"dotnet:%s-%s", lh.Version, fdkVersion), nil } func (h *DotnetLangHelper) DockerfileBuildCmds(localDebug bool) []string { diff --git a/langs/go.go b/langs/go.go index 0b47ceb3..c539dbf2 100644 --- a/langs/go.go +++ b/langs/go.go @@ -23,6 +23,8 @@ import ( "os" "path/filepath" "strings" + + "github.com/fnproject/cli/config" ) type GoLangHelper struct { @@ -49,11 +51,11 @@ func (lh *GoLangHelper) Extensions() []string { } func (lh *GoLangHelper) BuildFromImage() (string, error) { - return fmt.Sprintf("fnproject/go:%s-dev", lh.Version), nil + return fmt.Sprintf(config.OCRImagePrefix+"go:%s-dev", lh.Version), nil } func (lh *GoLangHelper) RunFromImage() (string, error) { - return fmt.Sprintf("fnproject/go:%s", lh.Version), nil + return fmt.Sprintf(config.OCRImagePrefix+"go:%s", lh.Version), nil } func (h *GoLangHelper) DockerfileBuildCmds(localDebug bool) []string { diff --git a/langs/java.go b/langs/java.go index a5fe8896..99f5de03 100644 --- a/langs/java.go +++ b/langs/java.go @@ -29,6 +29,8 @@ import ( "os" "path/filepath" "strings" + + "github.com/fnproject/cli/config" ) // JavaLangHelper provides a set of helper methods for the lifecycle of Java Maven projects @@ -63,13 +65,13 @@ func (h *JavaLangHelper) BuildFromImage() (string, error) { } if h.Version == "8" { - return fmt.Sprintf("fnproject/fn-java-fdk-build:%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk-build:%s", fdkVersion), nil } else if h.Version == "11" { - return fmt.Sprintf("fnproject/fn-java-fdk-build:jdk11-%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk-build:jdk11-%s", fdkVersion), nil } else if h.Version == "17" { - return fmt.Sprintf("fnproject/fn-java-fdk-build:jdk17-%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk-build:jdk17-%s", fdkVersion), nil } else if h.Version == "21" { - return fmt.Sprintf("fnproject/fn-java-fdk-build:jdk21-%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk-build:jdk21-%s", fdkVersion), nil } else { return "", fmt.Errorf("unsupported java version %s", h.Version) } @@ -82,13 +84,13 @@ func (h *JavaLangHelper) RunFromImage() (string, error) { return "", err } if h.Version == "8" { - return fmt.Sprintf("fnproject/fn-java-fdk:%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk:%s", fdkVersion), nil } else if h.Version == "11" { - return fmt.Sprintf("fnproject/fn-java-fdk:jre11-%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk:jre11-%s", fdkVersion), nil } else if h.Version == "17" { - return fmt.Sprintf("fnproject/fn-java-fdk:jre17-%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk:jre17-%s", fdkVersion), nil } else if h.Version == "21" { - return fmt.Sprintf("fnproject/fn-java-fdk:jre21-%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk:jre21-%s", fdkVersion), nil } else { return "", fmt.Errorf("unsupported java version %s", h.Version) } diff --git a/langs/kotlin.go b/langs/kotlin.go index 9a196999..a6b60fd4 100644 --- a/langs/kotlin.go +++ b/langs/kotlin.go @@ -25,6 +25,8 @@ import ( "os" "path/filepath" "strings" + + "github.com/fnproject/cli/config" ) // KotlinLangHelper provides a set of helper methods for the lifecycle of Kotlin Maven projects @@ -59,7 +61,7 @@ func (h *KotlinLangHelper) BuildFromImage() (string, error) { return "", err } - return fmt.Sprintf("fnproject/fn-java-fdk-build:jdk11-%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk-build:jdk11-%s", fdkVersion), nil } // RunFromImage returns the Docker image used to run the Kotlin function. @@ -69,7 +71,7 @@ func (h *KotlinLangHelper) RunFromImage() (string, error) { return "", err } - return fmt.Sprintf("fnproject/fn-java-fdk:jre11-%s", fdkVersion), nil + return fmt.Sprintf(config.OCRImagePrefix+"fn-java-fdk:jre11-%s", fdkVersion), nil } // HasBoilerplate returns whether the Java runtime has boilerplate that can be generated. diff --git a/langs/node.go b/langs/node.go index 1cc4b1b7..b0f11aec 100644 --- a/langs/node.go +++ b/langs/node.go @@ -23,6 +23,8 @@ import ( "net/http" "os" "path/filepath" + + "github.com/fnproject/cli/config" ) type NodeLangHelper struct { @@ -45,10 +47,10 @@ func (lh *NodeLangHelper) Extensions() []string { return []string{".js"} } func (lh *NodeLangHelper) BuildFromImage() (string, error) { - return fmt.Sprintf("fnproject/node:%s-dev", lh.Version), nil + return fmt.Sprintf(config.OCRImagePrefix+"node:%s-dev", lh.Version), nil } func (lh *NodeLangHelper) RunFromImage() (string, error) { - return fmt.Sprintf("fnproject/node:%s", lh.Version), nil + return fmt.Sprintf(config.OCRImagePrefix+"node:%s", lh.Version), nil } const funcJsContent = `const fdk=require('@fnproject/fdk'); diff --git a/langs/python.go b/langs/python.go index 0164d92d..b54c85f8 100644 --- a/langs/python.go +++ b/langs/python.go @@ -24,6 +24,8 @@ import ( "net/http" "os" "path/filepath" + + "github.com/fnproject/cli/config" ) // PythonLangHelper - python-specific init helper @@ -80,11 +82,11 @@ func (h *PythonLangHelper) Extensions() []string { } func (h *PythonLangHelper) BuildFromImage() (string, error) { - return fmt.Sprintf("fnproject/python:%s-dev", h.Version), nil + return fmt.Sprintf(config.OCRImagePrefix+"python:%s-dev", h.Version), nil } func (h *PythonLangHelper) RunFromImage() (string, error) { - return fmt.Sprintf("fnproject/python:%s", h.Version), nil + return fmt.Sprintf(config.OCRImagePrefix+"python:%s", h.Version), nil } func (h *PythonLangHelper) Entrypoint() (string, error) { diff --git a/langs/ruby.go b/langs/ruby.go index 841c57d5..440164fa 100644 --- a/langs/ruby.go +++ b/langs/ruby.go @@ -23,6 +23,8 @@ import ( "net/http" "os" "path/filepath" + + "github.com/fnproject/cli/config" ) type RubyLangHelper struct { @@ -50,10 +52,10 @@ func (h *RubyLangHelper) CustomMemory() uint64 { return 0 } func (h *RubyLangHelper) BuildFromImage() (string, error) { - return fmt.Sprintf("fnproject/ruby:%s-dev", h.Version), nil + return fmt.Sprintf(config.OCRImagePrefix+"ruby:%s-dev", h.Version), nil } func (h *RubyLangHelper) RunFromImage() (string, error) { - return fmt.Sprintf("fnproject/ruby:%s", h.Version), nil + return fmt.Sprintf(config.OCRImagePrefix+"ruby:%s", h.Version), nil } func (h *RubyLangHelper) DockerfileBuildCmds(localDebug bool) []string { diff --git a/langs/runtime_support_test.go b/langs/runtime_support_test.go index 3b252bc7..ece6c3cf 100644 --- a/langs/runtime_support_test.go +++ b/langs/runtime_support_test.go @@ -1,6 +1,10 @@ package langs -import "testing" +import ( + "testing" + + "github.com/fnproject/cli/config" +) func TestDefaultRuntimeVersions(t *testing.T) { tests := []struct { @@ -63,11 +67,11 @@ func TestNode24Images(t *testing.T) { t.Fatalf("RunFromImage() returned error: %v", err) } - if buildImage != "fnproject/node:24-dev" { - t.Fatalf("expected node24 build image %q, got %q", "fnproject/node:24-dev", buildImage) + if buildImage != config.OCRImagePrefix+"node:24-dev" { + t.Fatalf("expected node24 build image %q, got %q", config.OCRImagePrefix+"node:24-dev", buildImage) } - if runImage != "fnproject/node:24" { - t.Fatalf("expected node24 run image %q, got %q", "fnproject/node:24", runImage) + if runImage != config.OCRImagePrefix+"node:24" { + t.Fatalf("expected node24 run image %q, got %q", config.OCRImagePrefix+"node:24", runImage) } } @@ -83,11 +87,11 @@ func TestJava21Images(t *testing.T) { t.Fatalf("RunFromImage() returned error: %v", err) } - if buildImage != "fnproject/fn-java-fdk-build:jdk21-1.2.3" { - t.Fatalf("expected java21 build image %q, got %q", "fnproject/fn-java-fdk-build:jdk21-1.2.3", buildImage) + if buildImage != config.OCRImagePrefix+"fn-java-fdk-build:jdk21-1.2.3" { + t.Fatalf("expected java21 build image %q, got %q", config.OCRImagePrefix+"fn-java-fdk-build:jdk21-1.2.3", buildImage) } - if runImage != "fnproject/fn-java-fdk:jre21-1.2.3" { - t.Fatalf("expected java21 run image %q, got %q", "fnproject/fn-java-fdk:jre21-1.2.3", runImage) + if runImage != config.OCRImagePrefix+"fn-java-fdk:jre21-1.2.3" { + t.Fatalf("expected java21 run image %q, got %q", config.OCRImagePrefix+"fn-java-fdk:jre21-1.2.3", runImage) } } @@ -103,10 +107,10 @@ func TestPython312Images(t *testing.T) { t.Fatalf("RunFromImage() returned error: %v", err) } - if buildImage != "fnproject/python:3.12-dev" { - t.Fatalf("expected python3.12 build image %q, got %q", "fnproject/python:3.12-dev", buildImage) + if buildImage != config.OCRImagePrefix+"python:3.12-dev" { + t.Fatalf("expected python3.12 build image %q, got %q", config.OCRImagePrefix+"python:3.12-dev", buildImage) } - if runImage != "fnproject/python:3.12" { - t.Fatalf("expected python3.12 run image %q, got %q", "fnproject/python:3.12", runImage) + if runImage != config.OCRImagePrefix+"python:3.12" { + t.Fatalf("expected python3.12 run image %q, got %q", config.OCRImagePrefix+"python:3.12", runImage) } } diff --git a/test/cli_docker_runtime_test.go b/test/cli_docker_runtime_test.go index 0357dcb1..b940e327 100644 --- a/test/cli_docker_runtime_test.go +++ b/test/cli_docker_runtime_test.go @@ -17,18 +17,18 @@ package test import ( + "github.com/fnproject/cli/config" "github.com/fnproject/cli/testharness" "testing" ) -const dockerFile = `FROM golang:latest -FROM fnproject/go:dev as build-stage +const dockerFile = `FROM ` + config.OCRImagePrefix + `go:1.24-dev as build-stage WORKDIR /function WORKDIR /go/src/func/ ENV GO111MODULE=on COPY . . RUN go build -o func -v -FROM fnproject/go +FROM ` + config.OCRImagePrefix + `go:1.24 WORKDIR /function COPY --from=build-stage /go/src/func/func /function/ ENTRYPOINT ["./func"] diff --git a/test/cli_misc_test.go b/test/cli_misc_test.go index 36ec28d8..29970b58 100644 --- a/test/cli_misc_test.go +++ b/test/cli_misc_test.go @@ -25,6 +25,7 @@ import ( "testing" "github.com/fnproject/cli/common" + "github.com/fnproject/cli/config" "github.com/fnproject/cli/testharness" ) @@ -129,7 +130,7 @@ func TestSettingTimeoutWorks(t *testing.T) { h.Fn("invoke", appName, "another").AssertSuccess() } -//Memory doesn't seem to get persisted/returned +// Memory doesn't seem to get persisted/returned func TestSettingMemoryWorks(t *testing.T) { t.Parallel() @@ -180,8 +181,8 @@ func TestFuncYamlWithOCIManagedSettingsParsesInHarness(t *testing.T) { Version: "0.0.1", Runtime: "go", Entrypoint: "./func", - Build_image: "fnproject/go:dev", - Run_image: "fnproject/go", + Build_image: config.OCRImagePrefix + "go:1.24-dev", + Run_image: config.OCRImagePrefix + "go:1.24", Deploy: &common.FuncDeployConfig{ OCI: &common.OCIFunctionDeployConfig{ ProvisionedConcurrency: &common.OCIProvisionedConcurrencyConfig{