Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/user/gen-docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
* [kyma alpha hana map](/cli/user/gen-docs/kyma_alpha_hana_map.md)
* [kyma alpha kubeconfig](/cli/user/gen-docs/kyma_alpha_kubeconfig.md)
* [kyma alpha kubeconfig generate](/cli/user/gen-docs/kyma_alpha_kubeconfig_generate.md)
* [kyma alpha module](/cli/user/gen-docs/kyma_alpha_module.md)
* [kyma alpha module catalog](/cli/user/gen-docs/kyma_alpha_module_catalog.md)
* [kyma alpha provision](/cli/user/gen-docs/kyma_alpha_provision.md)
* [kyma alpha reference-instance](/cli/user/gen-docs/kyma_alpha_reference-instance.md)
* [kyma app](/cli/user/gen-docs/kyma_app.md)
Expand Down
2 changes: 2 additions & 0 deletions docs/user/gen-docs/_sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export default [
{ text: 'kyma alpha hana map', link: './gen-docs/kyma_alpha_hana_map' },
{ text: 'kyma alpha kubeconfig', link: './gen-docs/kyma_alpha_kubeconfig' },
{ text: 'kyma alpha kubeconfig generate', link: './gen-docs/kyma_alpha_kubeconfig_generate' },
{ text: 'kyma alpha module', link: './gen-docs/kyma_alpha_module' },
{ text: 'kyma alpha module catalog', link: './gen-docs/kyma_alpha_module_catalog' },
{ text: 'kyma alpha provision', link: './gen-docs/kyma_alpha_provision' },
{ text: 'kyma alpha reference-instance', link: './gen-docs/kyma_alpha_reference-instance' },
{ text: 'kyma app', link: './gen-docs/kyma_app' },
Expand Down
2 changes: 2 additions & 0 deletions docs/user/gen-docs/kyma_alpha.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ kyma alpha <command> [flags]
diagnose - Diagnose cluster health and configuration
hana - Manages an SAP HANA instance in the Kyma cluster
kubeconfig - Manages access to the Kyma cluster
module - Manages Kyma modules
provision - Provisions a Kyma cluster on SAP BTP
reference-instance - Adds an instance reference to a shared service instance
```
Expand All @@ -38,5 +39,6 @@ kyma alpha <command> [flags]
* [kyma alpha diagnose](kyma_alpha_diagnose.md) - Diagnose cluster health and configuration
* [kyma alpha hana](kyma_alpha_hana.md) - Manages an SAP HANA instance in the Kyma cluster
* [kyma alpha kubeconfig](kyma_alpha_kubeconfig.md) - Manages access to the Kyma cluster
* [kyma alpha module](kyma_alpha_module.md) - Manages Kyma modules
* [kyma alpha provision](kyma_alpha_provision.md) - Provisions a Kyma cluster on SAP BTP
* [kyma alpha reference-instance](kyma_alpha_reference-instance.md) - Adds an instance reference to a shared service instance
32 changes: 32 additions & 0 deletions docs/user/gen-docs/kyma_alpha_module.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# kyma alpha module

Manages Kyma modules.

## Synopsis

Use this command to manage modules in the Kyma cluster.

```bash
kyma alpha module <command> [flags]
```

## Available Commands

```text
catalog - Lists modules catalog
```

## Flags

```text
--context string The name of the kubeconfig context to use
-h, --help Help for the command
--kubeconfig string Path to the Kyma kubeconfig file
--show-extensions-error Prints a possible error when fetching extensions fails
--skip-extensions Skip fetching extensions from the target Kyma environment
```

## See also

* [kyma alpha](kyma_alpha.md) - Groups command prototypes for which the API may still change
* [kyma alpha module catalog](kyma_alpha_module_catalog.md) - Lists modules catalog
53 changes: 53 additions & 0 deletions docs/user/gen-docs/kyma_alpha_module_catalog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# kyma alpha module catalog

Lists modules catalog.

## Synopsis

Use this command to list all available Kyma modules.

```bash
kyma alpha module catalog [flags]
```

## Examples

```bash

# List all available modules from all origins
kyma module catalog

# List only official Kyma modules managed by KLM with SLA
kyma module catalog --origin kyma

# List only community modules (not officially supported)
kyma module catalog --origin community

# List only community modules already available on the cluster
kyma module catalog --origin cluster

# List modules from multiple origins
kyma module catalog --origin kyma,community

# Output catalog as JSON
kyma module catalog -o json

# List official Kyma modules in YAML format
kyma module catalog --origin kyma -o yaml
```

## Flags

```text
--origin stringSlice Specifies the source of the module (default "[kyma,community,cluster]")
-o, --output string Output format (Possible values: table, json, yaml)
--context string The name of the kubeconfig context to use
-h, --help Help for the command
--kubeconfig string Path to the Kyma kubeconfig file
--show-extensions-error Prints a possible error when fetching extensions fails
--skip-extensions Skip fetching extensions from the target Kyma environment
```

## See also

* [kyma alpha module](kyma_alpha_module.md) - Manages Kyma modules
2 changes: 2 additions & 0 deletions internal/cmd/alpha/alpha.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/kyma-project/cli.v3/internal/cmd/alpha/diagnose"
"github.com/kyma-project/cli.v3/internal/cmd/alpha/hana"
"github.com/kyma-project/cli.v3/internal/cmd/alpha/kubeconfig"
"github.com/kyma-project/cli.v3/internal/cmd/alpha/module"
"github.com/kyma-project/cli.v3/internal/cmd/alpha/provision"
"github.com/kyma-project/cli.v3/internal/cmd/alpha/referenceinstance"
"github.com/kyma-project/cli.v3/internal/cmdcommon"
Expand All @@ -25,6 +26,7 @@ func NewAlphaCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command {
cmd.AddCommand(referenceinstance.NewReferenceInstanceCMD(kymaConfig))
cmd.AddCommand(kubeconfig.NewKubeconfigCMD(kymaConfig))
cmd.AddCommand(diagnose.NewDiagnoseCMD(kymaConfig))
cmd.AddCommand(module.NewModuleCMD(kymaConfig))

return cmd
}
79 changes: 79 additions & 0 deletions internal/cmd/alpha/module/catalog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package module

import (
"github.com/kyma-project/cli.v3/internal/clierror"
"github.com/kyma-project/cli.v3/internal/cmdcommon"
"github.com/kyma-project/cli.v3/internal/cmdcommon/types"
"github.com/kyma-project/cli.v3/internal/modulesv2"
"github.com/kyma-project/cli.v3/internal/modulesv2/dtos"
"github.com/spf13/cobra"
)

type catalogV2Config struct {
*cmdcommon.KymaConfig

origin []string
outputFormat types.Format
}

func NewCatalogV2CMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command {
cfg := catalogV2Config{
KymaConfig: kymaConfig,
}

cmd := &cobra.Command{
Use: "catalog [flags]",
Short: "Lists modules catalog",
Long: `Use this command to list all available Kyma modules.`,
Example: `
# List all available modules from all origins
kyma module catalog

# List only official Kyma modules managed by KLM with SLA
kyma module catalog --origin kyma

# List only community modules (not officially supported)
kyma module catalog --origin community

# List only community modules already available on the cluster
kyma module catalog --origin cluster

# List modules from multiple origins
kyma module catalog --origin kyma,community

# Output catalog as JSON
kyma module catalog -o json

# List official Kyma modules in YAML format
kyma module catalog --origin kyma -o yaml`,
Run: func(_ *cobra.Command, _ []string) {
clierror.Check(catalogModules(&cfg))
},
}

cmd.Flags().StringSliceVar(&cfg.origin, "origin", []string{"kyma", "community", "cluster"}, "Specifies the source of the module")
cmd.Flags().VarP(&cfg.outputFormat, "output", "o", "Output format (Possible values: table, json, yaml)")

return cmd
}

func catalogModules(cfg *catalogV2Config) clierror.Error {
moduleOperations := modulesv2.NewModuleOperations(cmdcommon.NewKymaConfig())

catalogOperation, err := moduleOperations.Catalog()
if err != nil {
return clierror.Wrap(err, clierror.New("failed to execute the catalog command"))
}

catalogResult, err := catalogOperation.Run(cfg.Ctx, dtos.NewCatalogConfigFromOriginsList(cfg.origin))
if err != nil {
return clierror.Wrap(err, clierror.New("failed to list available modules from the target Kyma environment"))
}

err = modulesv2.RenderCatalog(catalogResult, cfg.outputFormat)
if err != nil {
return clierror.Wrap(err, clierror.New("failed to render catalog"))
}

return nil
}
19 changes: 19 additions & 0 deletions internal/cmd/alpha/module/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package module

import (
"github.com/kyma-project/cli.v3/internal/cmdcommon"
"github.com/spf13/cobra"
)

func NewModuleCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command {
cmd := &cobra.Command{
Use: "module <command> [flags]",
Aliases: []string{"modules"},
Short: "Manages Kyma modules",
Long: `Use this command to manage modules in the Kyma cluster.`,
}

cmd.AddCommand(NewCatalogV2CMD(kymaConfig))

return cmd
}
76 changes: 76 additions & 0 deletions internal/di/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package di

import (
"fmt"
"reflect"
)

// DIContainer is a simple dependency injection container for singleton instances
type DIContainer struct {
instances map[reflect.Type]interface{}
factories map[reflect.Type]Factory
}

type Factory func(container *DIContainer) (interface{}, error)

func NewDIContainer() *DIContainer {
return &DIContainer{
instances: make(map[reflect.Type]interface{}),
factories: make(map[reflect.Type]Factory),
}
}

// Get retrieves or creates a singleton instance of the specified type
func (c *DIContainer) Get(targetType reflect.Type) (interface{}, error) {
// Fast path: check if instance already exists
if instance, exists := c.instances[targetType]; exists {
return instance, nil
}

factory, exists := c.factories[targetType]

if !exists {
return nil, fmt.Errorf("no registration found for type %s", targetType.String())
}

// Create instance (without holding lock to allow nested dependency resolution)
instance, err := factory(c)
if err != nil {
return nil, fmt.Errorf("failed to create instance of type %s: %w", targetType.String(), err)
}

// Check if another goroutine created it while we were creating ours
if existing, exists := c.instances[targetType]; exists {
return existing, nil
}
c.instances[targetType] = instance

return instance, nil
}

// GetTyped is a generic helper to get a singleton instance with type safety
func GetTyped[T any](c *DIContainer) (T, error) {
var zero T
targetType := reflect.TypeOf((*T)(nil)).Elem()

instance, err := c.Get(targetType)
if err != nil {
return zero, err
}

typed, ok := instance.(T)
if !ok {
return zero, fmt.Errorf("instance is not of expected type %T", zero)
}

return typed, nil
}

// RegisterTyped is a generic helper to register a factory with type safety
// Usage: RegisterTyped[MyInterface](container, func(c *DIContainer) (MyInterface, error) { ... })
func RegisterTyped[T any](c *DIContainer, factory func(*DIContainer) (T, error)) {
targetType := reflect.TypeOf((*T)(nil)).Elem()
c.factories[targetType] = func(container *DIContainer) (interface{}, error) {
return factory(container)
}
}
57 changes: 57 additions & 0 deletions internal/modulesv2/catalog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package modulesv2

import (
"context"
"fmt"

"github.com/kyma-project/cli.v3/internal/modulesv2/dtos"
"github.com/kyma-project/cli.v3/internal/modulesv2/repository"
)

type CatalogService struct {
moduleTemplatesRepository repository.ModuleTemplatesRepository
clusterMetadataRepository repository.ClusterMetadataRepository
}

func NewCatalogService(
moduleTemplatesRepository repository.ModuleTemplatesRepository,
clusterMetadataRepository repository.ClusterMetadataRepository,
) *CatalogService {
return &CatalogService{
moduleTemplatesRepository: moduleTemplatesRepository,
clusterMetadataRepository: clusterMetadataRepository,
}
}

func (c *CatalogService) Run(ctx context.Context, catalogConfig *dtos.CatalogConfig) ([]dtos.CatalogResult, error) {
results := []dtos.CatalogResult{}

if c.isClusterManagedByKLM(ctx) && catalogConfig.ListKyma {
coreModules, err := c.moduleTemplatesRepository.ListCore(ctx)
if err != nil {
return nil, fmt.Errorf("failed to list core modules: %v", err)
}
results = append(results, dtos.CatalogResultFromCoreModuleTemplates(coreModules)...)
}

if catalogConfig.ListCluster {
localCommunityModules, err := c.moduleTemplatesRepository.ListLocalCommunity(ctx)
if err != nil {
return nil, fmt.Errorf("failed to list local community modules: %v", err)
}
results = append(results, dtos.CatalogResultFromCommunityModuleTemplates(localCommunityModules)...)
}

externalCommunityModules, err := c.moduleTemplatesRepository.ListExternalCommunity(ctx, catalogConfig.ExternalUrls)
if err != nil {
return nil, fmt.Errorf("failed to list external community modules: %v", err)
}
results = append(results, dtos.CatalogResultFromCommunityModuleTemplates(externalCommunityModules)...)

return results, nil
}

func (c *CatalogService) isClusterManagedByKLM(ctx context.Context) bool {
clusterMetadata := c.clusterMetadataRepository.Get(ctx)
return clusterMetadata.IsManagedByKLM
}
Loading