From ecc0916ef4023b74bf98d074274feae83cf7351a Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Mon, 24 Oct 2022 05:40:16 +0200 Subject: [PATCH] feat: defer OpenShift detection (#1375) Signed-off-by: Matej Vasek Signed-off-by: Matej Vasek --- cmd/build.go | 9 ++++++-- cmd/client.go | 48 ++++++++++++++++++------------------------ cmd/deploy.go | 6 +++++- cmd/run.go | 2 +- openshift/openshift.go | 25 ++++++++++++++++------ 5 files changed, 52 insertions(+), 38 deletions(-) diff --git a/cmd/build.go b/cmd/build.go index f82c4ff1..d3aa7b7b 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -9,6 +9,7 @@ import ( "github.com/AlecAivazis/survey/v2/terminal" "github.com/ory/viper" "github.com/spf13/cobra" + "knative.dev/func/openshift" "knative.dev/func/buildpacks" "knative.dev/func/config" @@ -62,7 +63,7 @@ and the image name is stored in the configuration file. cmd.Flags().StringP("builder-image", "", "", "builder image, either an as a an image name or a mapping name.\nSpecified value is stored in func.yaml (as 'builder' field) for subsequent builds. ($FUNC_BUILDER_IMAGE)") cmd.Flags().BoolP("confirm", "c", cfg.Confirm, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)") cmd.Flags().StringP("image", "i", "", "Full image name in the form [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry (Env: $FUNC_IMAGE)") - cmd.Flags().StringP("registry", "r", GetDefaultRegistry(), "Registry + namespace part of the image to build, ex 'quay.io/myuser'. The full image name is automatically determined (Env: $FUNC_REGISTRY)") + cmd.Flags().StringP("registry", "r", "", "Registry + namespace part of the image to build, ex 'quay.io/myuser'. The full image name is automatically determined (Env: $FUNC_REGISTRY)") cmd.Flags().BoolP("push", "u", false, "Attempt to push the function image after being successfully built") cmd.Flags().Lookup("push").NoOptDefVal = "true" // --push == --push=true cmd.Flags().StringP("platform", "", "", "Target platform to build (e.g. linux/amd64).") @@ -256,7 +257,7 @@ type buildConfig struct { } func newBuildConfig() buildConfig { - return buildConfig{ + cfg := buildConfig{ Image: viper.GetString("image"), Path: getPathFlag(), Registry: viper.GetString("registry"), @@ -267,6 +268,10 @@ func newBuildConfig() buildConfig { Push: viper.GetBool("push"), Platform: viper.GetString("platform"), } + if cfg.Registry == "" && openshift.IsOpenShift() { + cfg.Registry = openshift.GetDefaultRegistry() + } + return cfg } // Prompt the user with value of config members, allowing for interaractive changes. diff --git a/cmd/client.go b/cmd/client.go index fe2cc64a..83186b6a 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -109,13 +109,7 @@ func NewClient(cfg ClientConfig, options ...fn.Option) (*fn.Client, func()) { // newTransport returns a transport with cluster-flavor-specific variations // which take advantage of additional features offered by cluster variants. func newTransport(insecureSkipVerify bool) fnhttp.RoundTripCloser { - if openshift.IsOpenShift() { - return fnhttp.NewRoundTripper(fnhttp.WithInsecureSkipVerify(insecureSkipVerify), openshift.WithOpenShiftServiceCA()) - } - - // Other cluster variants ... - - return fnhttp.NewRoundTripper(fnhttp.WithInsecureSkipVerify(insecureSkipVerify)) // Default (vanilla k8s) + return fnhttp.NewRoundTripper(fnhttp.WithInsecureSkipVerify(insecureSkipVerify), openshift.WithOpenShiftServiceCA()) } // newCredentialsProvider returns a credentials provider which possibly @@ -126,12 +120,9 @@ func newCredentialsProvider(configPath string, t http.RoundTripper) docker.Crede creds.WithPromptForCredentials(newPromptForCredentials(os.Stdin, os.Stdout, os.Stderr)), creds.WithPromptForCredentialStore(newPromptForCredentialStore()), creds.WithTransport(t), + creds.WithAdditionalCredentialLoaders(openshift.GetDockerCredentialLoaders()...), } - // The OpenShift variant has additional ways to load credentials - if openshift.IsOpenShift() { - options = append(options, - creds.WithAdditionalCredentialLoaders(openshift.GetDockerCredentialLoaders()...)) - } + // Other cluster variants can be supported here return creds.NewCredentialsProvider(configPath, options...) } @@ -142,10 +133,7 @@ func newTektonPipelinesProvider(namespace string, progress *progress.Bar, creds tekton.WithProgressListener(progress), tekton.WithCredentialsProvider(creds), tekton.WithVerbose(verbose), - } - - if openshift.IsOpenShift() { - options = append(options, tekton.WithPipelineDecorator(openshift.OpenshiftMetadataDecorator{})) + tekton.WithPipelineDecorator(deployDecorator{}), } return tekton.NewPipelinesProvider(options...) @@ -155,20 +143,26 @@ func newKnativeDeployer(namespace string, verbose bool) fn.Deployer { options := []knative.DeployerOpt{ knative.WithDeployerNamespace(namespace), knative.WithDeployerVerbose(verbose), - } - - if openshift.IsOpenShift() { - options = append(options, knative.WithDeployerDecorator(openshift.OpenshiftMetadataDecorator{})) + knative.WithDeployerDecorator(deployDecorator{}), } return knative.NewDeployer(options...) } -func GetDefaultRegistry() string { - switch { - case openshift.IsOpenShift(): - return openshift.GetDefaultRegistry() - default: - return "" - } +type deployDecorator struct { + oshDec openshift.OpenshiftMetadataDecorator +} + +func (d deployDecorator) UpdateAnnotations(function fn.Function, annotations map[string]string) map[string]string { + if openshift.IsOpenShift() { + return d.oshDec.UpdateAnnotations(function, annotations) + } + return annotations +} + +func (d deployDecorator) UpdateLabels(function fn.Function, labels map[string]string) map[string]string { + if openshift.IsOpenShift() { + return d.oshDec.UpdateLabels(function, labels) + } + return labels } diff --git a/cmd/deploy.go b/cmd/deploy.go index 45ebaaac..9e096244 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -16,6 +16,7 @@ import ( "github.com/ory/viper" "github.com/spf13/cobra" "knative.dev/client/pkg/util" + "knative.dev/func/openshift" fn "knative.dev/func" "knative.dev/func/builders" @@ -145,7 +146,7 @@ EXAMPLES cmd.Flags().StringP("builder", "b", builders.Default, fmt.Sprintf("builder to use when creating the underlying image. Currently supported builders are %s.", KnownBuilders())) cmd.Flags().StringP("builder-image", "", "", "The image the specified builder should use; either an as an image name or a mapping. ($FUNC_BUILDER_IMAGE)") cmd.Flags().StringP("image", "i", "", "Full image name in the form [registry]/[namespace]/[name]:[tag]@[digest]. This option takes precedence over --registry. Specifying digest is optional, but if it is given, 'build' and 'push' phases are disabled. (Env: $FUNC_IMAGE)") - cmd.Flags().StringP("registry", "r", GetDefaultRegistry(), "Registry + namespace part of the image to build, ex 'ghcr.io/myuser'. The full image name is automatically determined. (Env: $FUNC_REGISTRY)") + cmd.Flags().StringP("registry", "r", "", "Registry + namespace part of the image to build, ex 'ghcr.io/myuser'. The full image name is automatically determined. (Env: $FUNC_REGISTRY)") cmd.Flags().BoolP("push", "u", true, "Push the function image to registry before deploying (Env: $FUNC_PUSH)") cmd.Flags().StringP("platform", "", "", "Target platform to build (e.g. linux/amd64).") cmd.Flags().StringP("namespace", "n", "", "Deploy into a specific namespace. (Env: $FUNC_NAMESPACE)") @@ -568,6 +569,9 @@ func newDeployConfig(cmd *cobra.Command) (deployConfig, error) { GitDir: viper.GetString("git-dir"), ImageDigest: "", // automatically split off --image if provided below } + if c.Registry == "" && openshift.IsOpenShift() { + c.Registry = openshift.GetDefaultRegistry() + } if c.Image, c.ImageDigest, err = parseImage(c.Image); err != nil { return c, err diff --git a/cmd/run.go b/cmd/run.go index 6ae79a69..d6898946 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -52,7 +52,7 @@ to the function's source. Use --build to override this behavior. "To unset, specify the environment variable name followed by a \"-\" (e.g., NAME-).") cmd.Flags().StringP("build", "b", "auto", "Build the function. [auto|true|false].") cmd.Flags().Lookup("build").NoOptDefVal = "true" // --build is equivalient to --build=true - cmd.Flags().StringP("registry", "r", GetDefaultRegistry(), "Registry + namespace part of the image if building, ex 'quay.io/myuser' (Env: $FUNC_REGISTRY)") + cmd.Flags().StringP("registry", "r", "", "Registry + namespace part of the image if building, ex 'quay.io/myuser' (Env: $FUNC_REGISTRY)") setPathFlag(cmd) cmd.SetHelpFunc(defaultTemplatedHelp) diff --git a/openshift/openshift.go b/openshift/openshift.go index 71de3e04..8efccc3f 100644 --- a/openshift/openshift.go +++ b/openshift/openshift.go @@ -5,6 +5,7 @@ import ( "crypto/x509" "encoding/pem" "errors" + "fmt" "strings" "sync" "time" @@ -89,16 +90,26 @@ func GetServiceCA(ctx context.Context) (*x509.Certificate, error) { // WithOpenShiftServiceCA enables trust to OpenShift's service CA for internal image registry func WithOpenShiftServiceCA() fnhttp.Option { - var selectCA func(ctx context.Context, serverName string) (*x509.Certificate, error) - ca, err := GetServiceCA(context.TODO()) - if err == nil { - selectCA = func(ctx context.Context, serverName string) (*x509.Certificate, error) { - if strings.HasPrefix(serverName, registryHost) { - return ca, nil + var err error + var ca *x509.Certificate + var o sync.Once + + selectCA := func(ctx context.Context, serverName string) (*x509.Certificate, error) { + if strings.HasPrefix(serverName, registryHost) { + o.Do(func() { + ca, err = GetServiceCA(ctx) + if err != nil { + err = fmt.Errorf("cannot get CA: %w", err) + } + }) + if err != nil { + return nil, err } - return nil, nil + return ca, nil } + return nil, nil } + return fnhttp.WithSelectCA(selectCA) }