diff --git a/internal/cmd/operator_describe.go b/internal/cmd/operator_describe.go index b833a339..e777b281 100644 --- a/internal/cmd/operator_describe.go +++ b/internal/cmd/operator_describe.go @@ -14,9 +14,9 @@ import ( var ( // output helpers for the describe subcommand + catHdr = asHeader("Catalog") pkgHdr = asHeader("Package") repoHdr = asHeader("Repository") - catHdr = asHeader("Catalog") chHdr = asHeader("Channels") imHdr = asHeader("Install Modes") sdHdr = asHeader("Description") @@ -46,53 +46,88 @@ func newOperatorDescribeCmd(cfg *action.Configuration) *cobra.Command { log.Fatal(err) } - // we only expect one item because describe always searches - // for a specific operator by name - pm := pms[0] - - pc, err := pm.GetChannel(channel) - if err != nil { - // the requested channel doesn't exist - log.Fatal(err) - } - // prepare what we want to print to the console out := make([]string, 0) - // Starting adding data to our output. - out = append(out, - // package - pkgHdr+fmt.Sprintf("%s %s (by %s)\n\n", - pc.CurrentCSVDesc.DisplayName, - pc.CurrentCSVDesc.Version, - pc.CurrentCSVDesc.Provider.Name), - // repo - repoHdr+fmt.Sprintf("%s\n\n", - pc.CurrentCSVDesc.Annotations[repoAnnot]), + // The PackageManifest API is a bit unusual, as it is namespace-scoped, but has the concept of a "Global" package. + // For Global catalogs, the PackageManifest is available to each namespace. + // The -n global parameter is ignored by this command + // Instead, the -c argument accepts a NamespacedName: [namespace][/][catalog-name] + // All catalogs: / + // All catalogs in one namespace: mynamespace/ + // All catalogs with the same name: /mycatalog + // mycatalog + // Specific catalog: mynamespace/mycatalog + + // If no namespace is explicitly selected, show the package in all available catalogs visible to the user. + // If a namespace is explicitly selected, show the package scoped to the catalogs in the specified namespace. + + for _, pm := range pms { + + globalScope := true + if pm.Namespace == pm.Status.CatalogSourceNamespace { + globalScope = false + } + // catalog - catHdr+fmt.Sprintf("%s\n\n", pm.Status.CatalogSourceDisplayName), - // available channels - chHdr+fmt.Sprintf("%s\n\n", - strings.Join(getAvailableChannelsWithMarkers(*pc, pm), "\n")), - // install modes - imHdr+fmt.Sprintf("%s\n\n", - strings.Join(pc.GetSupportedInstallModes().List(), "\n")), - // description - sdHdr+fmt.Sprintf("%s\n", - pc.CurrentCSVDesc.Annotations[descAnnot]), - ) - - // if the user requested a long description, add it to the output as well - if longDescription { + out = append(out, catHdr) + + if globalScope { + out = append(out, + "Scope: Global\n", + ) + } else { + out = append(out, + "Scope: Namespaced\n", + fmt.Sprintf("Namespace: %s\n", pm.Labels["catalog-namespace"]), + ) + } out = append(out, - "\n"+ldHdr+pm.Status.Channels[0].CurrentCSVDesc.LongDescription) - } + fmt.Sprintf("Name: %s\n", pm.Status.CatalogSource), + fmt.Sprintf("Display Name: %s\n", pm.Status.CatalogSourceDisplayName), + fmt.Sprintf("Publisher: %s\n\n", pm.Status.CatalogSourcePublisher), + ) + + pc, err := pm.GetChannel(channel) + if err != nil { + // the requested channel doesn't exist + log.Fatal(err) + } + + // Starting adding data to our output. + out = append(out, + // package + pkgHdr+fmt.Sprintf("%s %s (by %s)\n\n", + pc.CurrentCSVDesc.DisplayName, + pc.CurrentCSVDesc.Version, + pc.CurrentCSVDesc.Provider.Name), + // repo + repoHdr+fmt.Sprintf("%s\n\n", + pc.CurrentCSVDesc.Annotations[repoAnnot]), + // available channels + chHdr+fmt.Sprintf("%s\n\n", + strings.Join(getAvailableChannelsWithMarkers(*pc, pm), "\n")), + // install modes + imHdr+fmt.Sprintf("%s\n\n", + strings.Join(pc.GetSupportedInstallModes().List(), "\n")), + // description + sdHdr+fmt.Sprintf("%s\n", + pc.CurrentCSVDesc.Annotations[descAnnot]), + ) + + // if the user requested a long description, add it to the output as well + if longDescription { + out = append(out, + "\n"+ldHdr+pm.Status.Channels[0].CurrentCSVDesc.LongDescription) + } + + out = append(out, "\n") + } // finally, print operator information to the console for _, v := range out { fmt.Print(v) } - }, } diff --git a/internal/cmd/operator_list_available.go b/internal/cmd/operator_list_available.go index a4af3139..85ba9589 100644 --- a/internal/cmd/operator_list_available.go +++ b/internal/cmd/operator_list_available.go @@ -48,11 +48,15 @@ func newOperatorListAvailableCmd(cfg *action.Configuration) *cobra.Command { }) tw := tabwriter.NewWriter(os.Stdout, 3, 4, 2, ' ', 0) - _, _ = fmt.Fprintf(tw, "NAME\tCATALOG\tCHANNEL\tLATEST CSV\tAGE\n") + _, _ = fmt.Fprintf(tw, "NAME\tNAMESPACE\tCATALOG\tCHANNEL\tLATEST CSV\tAGE\n") for _, op := range operators { + ns := "" + if op.ObjectMeta.Namespace == op.Status.CatalogSourceNamespace { + ns = op.ObjectMeta.Namespace + } age := time.Since(op.CreationTimestamp.Time) for _, ch := range op.Status.Channels { - _, _ = fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\n", op.Name, op.Status.CatalogSourceDisplayName, ch.Name, ch.CurrentCSV, duration.HumanDuration(age)) + _, _ = fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t%s\n", op.Name, ns, op.Status.CatalogSourceDisplayName, ch.Name, ch.CurrentCSV, duration.HumanDuration(age)) } } _ = tw.Flush() diff --git a/internal/pkg/action/operator_list_available.go b/internal/pkg/action/operator_list_available.go index 09c253d7..de49d6cd 100644 --- a/internal/pkg/action/operator_list_available.go +++ b/internal/pkg/action/operator_list_available.go @@ -36,13 +36,15 @@ func (l *OperatorListAvailable) Run(ctx context.Context) ([]operator.PackageMani } pms := v1.PackageManifestList{} - if err := l.config.Client.List(ctx, &pms, labelSelector); err != nil { + + options := client.ListOptions{Namespace: l.config.Namespace} + if err := l.config.Client.List(ctx, &pms, labelSelector, &options); err != nil { return nil, err } - pkgs := make([]operator.PackageManifest, len(pms.Items)) + pkgs := make([]operator.PackageManifest, 0, len(pms.Items)) for i := range pms.Items { if l.Package == "" || l.Package == pms.Items[i].GetName() { - pkgs[i] = operator.PackageManifest{PackageManifest: pms.Items[i]} + pkgs = append(pkgs, operator.PackageManifest{PackageManifest: pms.Items[i]}) } } return pkgs, nil