From 46bb4d2a3c01ab30c5ee654fca61ea63aa80f78d Mon Sep 17 00:00:00 2001 From: Michael Nelson Date: Tue, 29 Aug 2023 11:32:26 +1000 Subject: [PATCH 1/2] Pass OCI Catalog URL through to syncer. Signed-off-by: Michael Nelson --- .../templates/apprepository/deployment.yaml | 4 ++++ .../kubeapps/templates/kubeappsapis/deployment.yaml | 2 ++ chart/kubeapps/templates/kubeappsapis/service.yaml | 6 ++++++ cmd/apprepository-controller/cmd/root.go | 6 +++++- cmd/apprepository-controller/server/job_utils.go | 6 ++++++ cmd/apprepository-controller/server/server.go | 1 + cmd/asset-syncer/cmd/root.go | 1 + cmd/asset-syncer/server/sync.go | 13 ++++++++++++- cmd/asset-syncer/server/utils.go | 7 ++++--- 9 files changed, 41 insertions(+), 5 deletions(-) diff --git a/chart/kubeapps/templates/apprepository/deployment.yaml b/chart/kubeapps/templates/apprepository/deployment.yaml index 02a668da752..a52f63a8278 100644 --- a/chart/kubeapps/templates/apprepository/deployment.yaml +++ b/chart/kubeapps/templates/apprepository/deployment.yaml @@ -128,6 +128,10 @@ spec: env: - name: REPO_SYNC_IMAGE value: {{ include "kubeapps.apprepository.syncImage" . }} + {{- if .Values.ociCatalog.enabled }} + - name: OCI_CATALOG_URL + value: {{ printf "%s:%d" (include "kubeapps.kubeappsapis.fullname" .) (int .Values.ociCatalog.containerPorts.grpc) | quote }} + {{- end }} {{- if .Values.apprepository.extraEnvVars }} {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.extraEnvVars "context" $) | nindent 12 }} {{- end }} diff --git a/chart/kubeapps/templates/kubeappsapis/deployment.yaml b/chart/kubeapps/templates/kubeappsapis/deployment.yaml index 0c116ea5c26..44852938c94 100644 --- a/chart/kubeapps/templates/kubeappsapis/deployment.yaml +++ b/chart/kubeapps/templates/kubeappsapis/deployment.yaml @@ -166,9 +166,11 @@ spec: secretKeyRef: key: postgres-password name: {{ include "kubeapps.postgresql.secretName" . }} + {{- if .Values.ociCatalog.enabled }} - name: OCI_CATALOG_URL value: {{ printf ":%d" (int .Values.ociCatalog.containerPorts.grpc) | quote }} {{- end }} + {{- end }} {{- if .Values.kubeappsapis.extraEnvVars }} {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.extraEnvVars "context" $) | nindent 12 }} {{- end }} diff --git a/chart/kubeapps/templates/kubeappsapis/service.yaml b/chart/kubeapps/templates/kubeappsapis/service.yaml index f2887eeb2fd..9217718ad57 100644 --- a/chart/kubeapps/templates/kubeappsapis/service.yaml +++ b/chart/kubeapps/templates/kubeappsapis/service.yaml @@ -29,5 +29,11 @@ spec: targetPort: grpc-http protocol: TCP name: grpc-http + {{- if .Values.ociCatalog.enabled }} + - port: {{ .Values.ociCatalog.containerPorts.grpc }} + targetPort: grpc + protocol: TCP + name: grpc + {{- end }} selector: {{- include "common.labels.matchLabels" . | nindent 4 }} app.kubernetes.io/component: kubeappsapis diff --git a/cmd/apprepository-controller/cmd/root.go b/cmd/apprepository-controller/cmd/root.go index 8ef7e384eb9..1f87b0e64f2 100644 --- a/cmd/apprepository-controller/cmd/root.go +++ b/cmd/apprepository-controller/cmd/root.go @@ -5,6 +5,7 @@ package cmd import ( "flag" + "os" "strings" "github.com/spf13/cobra" @@ -47,6 +48,9 @@ func initServerOpts() { serveOpts.ImagePullSecretsRefs = getImagePullSecretsRefs(serveOpts.RepoSyncImagePullSecrets) serveOpts.ParsedCustomAnnotations = parseLabelsAnnotations(serveOpts.CustomAnnotations) serveOpts.ParsedCustomLabels = parseLabelsAnnotations(serveOpts.CustomLabels) + if serveOpts.OciCatalogUrl == "" { + serveOpts.OciCatalogUrl = os.Getenv("OCI_CATALOG_URL") + } } // Execute adds all child commands to the root command and sets flags appropriately. @@ -92,12 +96,12 @@ func setFlags(c *cobra.Command) { c.Flags().StringSliceVar(&serveOpts.CustomAnnotations, "custom-annotations", []string{""}, "Optional annotations to be passed to the generated CronJobs, Jobs and Pods objects. For example: my/annotation=foo") c.Flags().StringSliceVar(&serveOpts.CustomLabels, "custom-labels", []string{""}, "Optional labels to be passed to the generated CronJobs, Jobs and Pods objects. For example: my/label=foo") c.Flags().BoolVar(&serveOpts.V1Beta1CronJobs, "v1-beta1-cron-jobs", false, "Defaults to false and so using the v1 cronjobs.") + c.Flags().StringVar(&serveOpts.OciCatalogUrl, "oci-catalog-url", "", "URL for gRPC OCI Catalog service") } // initConfig reads in config file and ENV variables if set. func initConfig() { viper.AutomaticEnv() // read in environment variables that match - // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { log.Infof("Using config file: %v", viper.ConfigFileUsed()) diff --git a/cmd/apprepository-controller/server/job_utils.go b/cmd/apprepository-controller/server/job_utils.go index 7b1cfee3c70..8c0a7a197d0 100644 --- a/cmd/apprepository-controller/server/job_utils.go +++ b/cmd/apprepository-controller/server/job_utils.go @@ -163,6 +163,12 @@ func apprepoJobEnvVars(apprepo *apprepov1alpha1.AppRepository, config Config) [] }, }, }) + if config.OciCatalogUrl != "" { + envVars = append(envVars, corev1.EnvVar{ + Name: "OCI_CATALOG_URL", + Value: config.OciCatalogUrl, + }) + } if apprepo.Spec.Auth.Header != nil { if apprepo.Spec.Auth.Header.SecretKeyRef.Key == ".dockerconfigjson" { envVars = append(envVars, corev1.EnvVar{ diff --git a/cmd/apprepository-controller/server/server.go b/cmd/apprepository-controller/server/server.go index 37b5924bb70..a728cfb5333 100644 --- a/cmd/apprepository-controller/server/server.go +++ b/cmd/apprepository-controller/server/server.go @@ -41,6 +41,7 @@ type Config struct { ParsedCustomAnnotations map[string]string ParsedCustomLabels map[string]string V1Beta1CronJobs bool + OciCatalogUrl string } func Serve(serveOpts Config) error { diff --git a/cmd/asset-syncer/cmd/root.go b/cmd/asset-syncer/cmd/root.go index dd5c77810b0..953213d9dd8 100644 --- a/cmd/asset-syncer/cmd/root.go +++ b/cmd/asset-syncer/cmd/root.go @@ -115,6 +115,7 @@ func init() { serveOpts.KubeappsNamespace = os.Getenv("POD_NAMESPACE") serveOpts.AuthorizationHeader = os.Getenv("AUTHORIZATION_HEADER") serveOpts.DockerConfigJson = os.Getenv("DOCKER_CONFIG_JSON") + serveOpts.OCICatalogURL = os.Getenv("OCI_CATALOG_URL") } func setRootFlags(c *cobra.Command) { diff --git a/cmd/asset-syncer/server/sync.go b/cmd/asset-syncer/server/sync.go index 8cf73f326a0..4d82a9598b9 100644 --- a/cmd/asset-syncer/server/sync.go +++ b/cmd/asset-syncer/server/sync.go @@ -9,10 +9,12 @@ import ( "fmt" "time" + ocicatalog "github.com/vmware-tanzu/kubeapps/cmd/oci-catalog/gen/catalog/v1alpha1" "github.com/vmware-tanzu/kubeapps/pkg/chart/models" "github.com/vmware-tanzu/kubeapps/pkg/dbutils" httpclient "github.com/vmware-tanzu/kubeapps/pkg/http-client" "github.com/vmware-tanzu/kubeapps/pkg/kube" + "github.com/vmware-tanzu/kubeapps/pkg/ocicatalog_client" log "k8s.io/klog/v2" ) @@ -62,7 +64,16 @@ func Sync(serveOpts Config, version string, args []string) error { if args[2] == "helm" { repoIface, err = getHelmRepo(serveOpts.Namespace, args[0], args[1], authorizationHeader, filters, netClient, serveOpts.UserAgent) } else { - repoIface, err = getOCIRepo(serveOpts.Namespace, args[0], args[1], authorizationHeader, filters, serveOpts.OciRepositories, netClient) + var grpcClient ocicatalog.OCICatalogServiceClient + if serveOpts.OCICatalogURL != "" { + var closer func() + grpcClient, closer, err = ocicatalog_client.NewClient(serveOpts.OCICatalogURL) + if err != nil { + return fmt.Errorf("unable to create oci catalog client: %w", err) + } + defer closer() + } + repoIface, err = getOCIRepo(serveOpts.Namespace, args[0], args[1], authorizationHeader, filters, serveOpts.OciRepositories, netClient, &grpcClient) } if err != nil { return fmt.Errorf("error: %v", err) diff --git a/cmd/asset-syncer/server/utils.go b/cmd/asset-syncer/server/utils.go index 46da7cb531d..30996632b60 100644 --- a/cmd/asset-syncer/server/utils.go +++ b/cmd/asset-syncer/server/utils.go @@ -62,6 +62,7 @@ type Config struct { KubeappsNamespace string AuthorizationHeader string DockerConfigJson string + OCICatalogURL string } type importChartFilesJob struct { @@ -491,7 +492,7 @@ func (o *OciAPIClient) Catalog(ctx context.Context, userAgent string) ([]string, return o.getVACReposForManifest(manifest, userAgent) } if o.GrpcClient != nil { - log.Infof("Unable to find VAC index: %+v. Attempting OCI-Catalog") + log.Infof("Unable to find VAC index: %+v. Attempting OCI-Catalog", err) repos_stream, err := o.GrpcClient.ListRepositoriesForRegistry(ctx, &ocicatalog.ListRepositoriesForRegistryRequest{ Registry: o.RegistryNamespaceUrl.Host, Namespace: o.RegistryNamespaceUrl.Path, @@ -805,7 +806,7 @@ func getHelmRepo(namespace, name, repoURL, authorizationHeader string, filter *a }, nil } -func getOCIRepo(namespace, name, repoURL, authorizationHeader string, filter *apprepov1alpha1.FilterRuleSpec, ociRepos []string, netClient *http.Client) (ChartCatalog, error) { +func getOCIRepo(namespace, name, repoURL, authorizationHeader string, filter *apprepov1alpha1.FilterRuleSpec, ociRepos []string, netClient *http.Client, grpcClient *ocicatalog.OCICatalogServiceClient) (ChartCatalog, error) { url, err := parseRepoURL(repoURL) if err != nil { log.Errorf("Failed to parse URL, url=%s: %v", repoURL, err) @@ -828,7 +829,7 @@ func getOCIRepo(namespace, name, repoURL, authorizationHeader string, filter *ap repositories: ociRepos, AppRepositoryInternal: &models.AppRepositoryInternal{Namespace: namespace, Name: name, URL: url.String(), AuthorizationHeader: authorizationHeader}, puller: &helm.OCIPuller{Resolver: ociResolver}, - ociCli: &OciAPIClient{RegistryNamespaceUrl: url, HttpClient: netClient}, + ociCli: &OciAPIClient{RegistryNamespaceUrl: url, HttpClient: netClient, GrpcClient: *grpcClient}, filter: filter, }, nil } From 127d6483270c74be19ecded0e7637912224e76a1 Mon Sep 17 00:00:00 2001 From: Michael Nelson Date: Tue, 29 Aug 2023 12:46:36 +1000 Subject: [PATCH 2/2] Fix tests. Signed-off-by: Michael Nelson --- cmd/asset-syncer/server/utils_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/asset-syncer/server/utils_test.go b/cmd/asset-syncer/server/utils_test.go index 9c9c02f752e..1838c30976c 100644 --- a/cmd/asset-syncer/server/utils_test.go +++ b/cmd/asset-syncer/server/utils_test.go @@ -311,14 +311,17 @@ func Test_syncURLInvalidity(t *testing.T) { } func Test_getOCIRepo(t *testing.T) { + grpcClient, f, err := ocicatalog_client.NewClient("test") + assert.NoError(t, err) + defer f() t.Run("it should add the auth header to the resolver", func(t *testing.T) { - repo, err := getOCIRepo("namespace", "test", "https://test", "Basic auth", nil, []string{}, &http.Client{}) + repo, err := getOCIRepo("namespace", "test", "https://test", "Basic auth", nil, []string{}, &http.Client{}, &grpcClient) assert.NoError(t, err) helmtest.CheckHeader(t, repo.(*OCIRegistry).puller, "Authorization", "Basic auth") }) t.Run("it should use https for distribution spec API calls if protocol is oci", func(t *testing.T) { - repo, err := getOCIRepo("namespace", "test", "oci://test", "Basic auth", nil, []string{}, &http.Client{}) + repo, err := getOCIRepo("namespace", "test", "oci://test", "Basic auth", nil, []string{}, &http.Client{}, &grpcClient) assert.NoError(t, err) client := repo.(*OCIRegistry).ociCli