Skip to content

Commit 3b2c08b

Browse files
committed
Add commands to list and get olmv1 operators and catalogs
Signed-off-by: Artur Zych <[email protected]>
1 parent 1acf90b commit 3b2c08b

File tree

9 files changed

+257
-0
lines changed

9 files changed

+257
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/onsi/gomega v1.36.2
1212
github.com/opencontainers/image-spec v1.1.0
1313
github.com/operator-framework/api v0.29.0
14+
github.com/operator-framework/catalogd v1.1.0
1415
github.com/operator-framework/operator-controller v1.1.0
1516
github.com/operator-framework/operator-lifecycle-manager v0.23.1
1617
github.com/operator-framework/operator-registry v1.50.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE
242242
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
243243
github.com/operator-framework/api v0.29.0 h1:TxAR8RCO+I4FjRrY4PSMgnlmbxNWeD8pzHXp7xwHNmw=
244244
github.com/operator-framework/api v0.29.0/go.mod h1:0whQE4mpMDd2zyHkQe+bFa3DLoRs6oGWCbu8dY/3pyc=
245+
github.com/operator-framework/catalogd v1.1.0 h1:mu2DYL5mpREEAAP+uPG+CMSsfsJkgrIasgLRG8nvwJg=
246+
github.com/operator-framework/catalogd v1.1.0/go.mod h1:8Je9CqMPwhNgRoqGX5OPsLYHsEoTDvPnELLLKRw1RHE=
245247
github.com/operator-framework/operator-controller v1.1.0 h1:h0b1SSuv9ZiIgI8dTuutSPVL4uIeyvTW3gOB2szkBMQ=
246248
github.com/operator-framework/operator-controller v1.1.0/go.mod h1:dJIt5/gfm1n3y9IeX4kpSlpu4CFq8WFVHU2n9ZDVUkA=
247249
github.com/operator-framework/operator-lifecycle-manager v0.23.1 h1:Xw2ml1T4W2ieoFaVwanW/eFlZ11yAOJZUpUI8RLSql8=
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package olmv1
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
6+
"github.com/operator-framework/kubectl-operator/internal/cmd/internal/log"
7+
v1action "github.com/operator-framework/kubectl-operator/internal/pkg/v1/action"
8+
"github.com/operator-framework/kubectl-operator/pkg/action"
9+
)
10+
11+
// NewCatalogInstalledGetCmd handles get commands in the form of:
12+
// catalog(s) [operatorName] - this will either list all the installed operators
13+
// if no operatorName has been provided or display the details of the specific
14+
// one otherwise
15+
func NewCatalogInstalledGetCmd(cfg *action.Configuration) *cobra.Command {
16+
i := v1action.NewCatalogInstalledGet(cfg)
17+
i.Logf = log.Printf
18+
19+
cmd := &cobra.Command{
20+
Use: "catalog",
21+
Aliases: []string{"catalogs"},
22+
Args: cobra.RangeArgs(0, 1),
23+
Short: "Display one or many installed catalogs",
24+
Run: func(cmd *cobra.Command, args []string) {
25+
if len(args) == 1 {
26+
i.CatalogName = args[0]
27+
}
28+
installedCatalogs, err := i.Run(cmd.Context())
29+
if err != nil {
30+
log.Fatalf("failed getting installed catalog(s): %v", err)
31+
}
32+
33+
printFormattedCatalogs(installedCatalogs...)
34+
},
35+
}
36+
37+
return cmd
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package olmv1
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
6+
"github.com/operator-framework/kubectl-operator/internal/cmd/internal/log"
7+
v1action "github.com/operator-framework/kubectl-operator/internal/pkg/v1/action"
8+
"github.com/operator-framework/kubectl-operator/pkg/action"
9+
)
10+
11+
// NewOperatorInstalledGetCmd handles get commands in the form of:
12+
// operator(s) [operatorName] - this will either list all the installed operators
13+
// if no operatorName has been provided or display the details of the specific
14+
// one otherwise
15+
func NewOperatorInstalledGetCmd(cfg *action.Configuration) *cobra.Command {
16+
i := v1action.NewOperatorInstalledGet(cfg)
17+
i.Logf = log.Printf
18+
19+
cmd := &cobra.Command{
20+
Use: "operator",
21+
Aliases: []string{"operators"},
22+
Args: cobra.RangeArgs(0, 1),
23+
Short: "Display one or many installed operators",
24+
Run: func(cmd *cobra.Command, args []string) {
25+
if len(args) == 1 {
26+
i.OperatorName = args[0]
27+
}
28+
installedExtensions, err := i.Run(cmd.Context())
29+
if err != nil {
30+
log.Fatalf("failed getting installed operator(s): %v", err)
31+
}
32+
33+
printFormattedOperators(installedExtensions...)
34+
},
35+
}
36+
37+
return cmd
38+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package olmv1
2+
3+
import (
4+
"cmp"
5+
"fmt"
6+
"os"
7+
"slices"
8+
"text/tabwriter"
9+
"time"
10+
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/util/duration"
13+
14+
catalogdv1 "github.com/operator-framework/catalogd/api/v1"
15+
olmv1 "github.com/operator-framework/operator-controller/api/v1"
16+
)
17+
18+
func printFormattedOperators(extensions ...olmv1.ClusterExtension) {
19+
tw := tabwriter.NewWriter(os.Stdout, 3, 4, 2, ' ', 0)
20+
_, _ = fmt.Fprint(tw, "NAME\tINSTALLED BUNDLE\tVERSION\tSOURCE TYPE\tINSTALLED\tPROGRESSING\tAGE\n")
21+
22+
// sort by name
23+
slices.SortFunc(extensions, func(a, b olmv1.ClusterExtension) int {
24+
return cmp.Compare(a.Name, b.Name)
25+
})
26+
27+
for _, ext := range extensions {
28+
age := time.Since(ext.CreationTimestamp.Time)
29+
_, _ = fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
30+
ext.Name,
31+
ext.Status.Install.Bundle.Name,
32+
ext.Status.Install.Bundle.Version,
33+
ext.Spec.Source.SourceType,
34+
status(ext.Status.Conditions, olmv1.TypeInstalled),
35+
status(ext.Status.Conditions, olmv1.TypeProgressing),
36+
duration.HumanDuration(age),
37+
)
38+
}
39+
_ = tw.Flush()
40+
}
41+
42+
func printFormattedCatalogs(catalogs ...catalogdv1.ClusterCatalog) {
43+
tw := tabwriter.NewWriter(os.Stdout, 3, 4, 2, ' ', 0)
44+
_, _ = fmt.Fprint(tw, "NAME\tAVAILABILITY\tPRIORITY\tLASTUNPACKED\tSERVING\tAGE\n")
45+
46+
// sort by availability first, then by priority and name
47+
slices.SortFunc(catalogs, func(a, b catalogdv1.ClusterCatalog) int {
48+
return cmp.Or(
49+
cmp.Compare(a.Spec.AvailabilityMode, a.Spec.AvailabilityMode),
50+
cmp.Compare(a.Spec.Priority, b.Spec.Priority),
51+
cmp.Compare(a.Name, b.Name),
52+
)
53+
})
54+
55+
for _, cat := range catalogs {
56+
age := time.Since(cat.CreationTimestamp.Time)
57+
lastUnpacked := time.Since(cat.Status.LastUnpacked.Time)
58+
_, _ = fmt.Fprintf(tw, "%s\t%s\t%d\t%s\t%s\t%s\n",
59+
cat.Name,
60+
string(cat.Spec.AvailabilityMode),
61+
cat.Spec.Priority,
62+
duration.HumanDuration(lastUnpacked),
63+
status(cat.Status.Conditions, catalogdv1.TypeServing),
64+
duration.HumanDuration(age),
65+
)
66+
}
67+
_ = tw.Flush()
68+
}
69+
70+
func status(conditions []metav1.Condition, typ string) string {
71+
for _, condition := range conditions {
72+
if condition.Type == typ {
73+
return string(condition.Status)
74+
}
75+
}
76+
77+
return "Unknown"
78+
}

internal/cmd/olmv1.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,20 @@ func newOlmV1Cmd(cfg *action.Configuration) *cobra.Command {
1414
Long: "Manage operators via OLMv1 in a cluster from the command line.",
1515
}
1616

17+
getCmd := &cobra.Command{
18+
Use: "get",
19+
Short: "Display one or many OLMv1-specific resource(s)",
20+
Long: "Display one or many OLMv1-specific resource(s)",
21+
}
22+
getCmd.AddCommand(
23+
olmv1.NewOperatorInstalledGetCmd(cfg),
24+
olmv1.NewCatalogInstalledGetCmd(cfg),
25+
)
26+
1727
cmd.AddCommand(
1828
olmv1.NewOperatorInstallCmd(cfg),
1929
olmv1.NewOperatorUninstallCmd(cfg),
30+
getCmd,
2031
)
2132

2233
return cmd
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package action
2+
3+
import (
4+
"context"
5+
6+
"k8s.io/apimachinery/pkg/types"
7+
"sigs.k8s.io/controller-runtime/pkg/client"
8+
9+
olmv1catalogd "github.com/operator-framework/catalogd/api/v1"
10+
11+
"github.com/operator-framework/kubectl-operator/pkg/action"
12+
)
13+
14+
type CatalogInstalledGet struct {
15+
config *action.Configuration
16+
CatalogName string
17+
18+
Logf func(string, ...interface{})
19+
}
20+
21+
func NewCatalogInstalledGet(cfg *action.Configuration) *CatalogInstalledGet {
22+
return &CatalogInstalledGet{
23+
config: cfg,
24+
Logf: func(string, ...interface{}) {},
25+
}
26+
}
27+
28+
func (i *CatalogInstalledGet) Run(ctx context.Context) ([]olmv1catalogd.ClusterCatalog, error) {
29+
// get
30+
if i.CatalogName != "" {
31+
var result olmv1catalogd.ClusterCatalog
32+
33+
opKey := types.NamespacedName{Name: i.CatalogName}
34+
err := i.config.Client.Get(ctx, opKey, &result)
35+
36+
return []olmv1catalogd.ClusterCatalog{result}, err
37+
}
38+
39+
// list
40+
var result olmv1catalogd.ClusterCatalogList
41+
err := i.config.Client.List(ctx, &result, &client.ListOptions{})
42+
43+
return result.Items, err
44+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package action
2+
3+
import (
4+
"context"
5+
6+
"k8s.io/apimachinery/pkg/types"
7+
"sigs.k8s.io/controller-runtime/pkg/client"
8+
9+
olmv1 "github.com/operator-framework/operator-controller/api/v1"
10+
11+
"github.com/operator-framework/kubectl-operator/pkg/action"
12+
)
13+
14+
type OperatorInstalledGet struct {
15+
config *action.Configuration
16+
OperatorName string
17+
18+
Logf func(string, ...interface{})
19+
}
20+
21+
func NewOperatorInstalledGet(cfg *action.Configuration) *OperatorInstalledGet {
22+
return &OperatorInstalledGet{
23+
config: cfg,
24+
Logf: func(string, ...interface{}) {},
25+
}
26+
}
27+
28+
func (i *OperatorInstalledGet) Run(ctx context.Context) ([]olmv1.ClusterExtension, error) {
29+
// get
30+
if i.OperatorName != "" {
31+
var result olmv1.ClusterExtension
32+
opKey := types.NamespacedName{Name: i.OperatorName}
33+
err := i.config.Client.Get(ctx, opKey, &result)
34+
35+
return []olmv1.ClusterExtension{result}, err
36+
}
37+
38+
// list
39+
var result olmv1.ClusterExtensionList
40+
err := i.config.Client.List(ctx, &result, &client.ListOptions{})
41+
42+
return result.Items, err
43+
}

pkg/action/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
v1 "github.com/operator-framework/api/pkg/operators/v1"
1313
"github.com/operator-framework/api/pkg/operators/v1alpha1"
14+
catalogdv1 "github.com/operator-framework/catalogd/api/v1"
1415
olmv1 "github.com/operator-framework/operator-controller/api/v1"
1516
operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
1617
)
@@ -23,6 +24,7 @@ func NewScheme() (*runtime.Scheme, error) {
2324
v1.AddToScheme,
2425
apiextensionsv1.AddToScheme,
2526
olmv1.AddToScheme,
27+
catalogdv1.AddToScheme,
2628
} {
2729
if err := f(sch); err != nil {
2830
return nil, err

0 commit comments

Comments
 (0)