diff --git a/pkg/cmd/get/packages.go b/pkg/cmd/get/packages.go new file mode 100644 index 00000000..d270dcf2 --- /dev/null +++ b/pkg/cmd/get/packages.go @@ -0,0 +1,129 @@ +package get + +import ( + "context" + "fmt" + "github.com/cnoe-io/idpbuilder/api/v1alpha1" + "github.com/cnoe-io/idpbuilder/pkg/build" + "github.com/cnoe-io/idpbuilder/pkg/entity" + "github.com/cnoe-io/idpbuilder/pkg/k8s" + "github.com/cnoe-io/idpbuilder/pkg/printer" + "github.com/spf13/cobra" + "io" + "k8s.io/client-go/util/homedir" + "os" + "path/filepath" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var PackagesCmd = &cobra.Command{ + Use: "packages", + Short: "retrieve packages from the cluster", + Long: ``, + RunE: getPackagesE, + SilenceUsage: true, +} + +func getPackagesE(cmd *cobra.Command, args []string) error { + ctx, ctxCancel := context.WithCancel(cmd.Context()) + defer ctxCancel() + kubeConfigPath := filepath.Join(homedir.HomeDir(), ".kube", "config") + + opts := build.NewBuildOptions{ + KubeConfigPath: kubeConfigPath, + Scheme: k8s.GetScheme(), + CancelFunc: ctxCancel, + } + + b := build.NewBuild(opts) + + kubeConfig, err := b.GetKubeConfig() + if err != nil { + return fmt.Errorf("getting kube config: %w", err) + } + + kubeClient, err := b.GetKubeClient(kubeConfig) + if err != nil { + return fmt.Errorf("getting kube client: %w", err) + } + + return printPackages(ctx, os.Stdout, kubeClient, outputFormat) +} + +// Print all the custom packages or based on package arguments passed using flag: -p +func printPackages(ctx context.Context, outWriter io.Writer, kubeClient client.Client, format string) error { + packageList := []entity.Package{} + customPackages := v1alpha1.CustomPackageList{} + var err error + + idpbuilderNamespace, err := getIDPNamespace(ctx, kubeClient) + if err != nil { + return fmt.Errorf("calculating idp namespace: %w", err) + } + + if len(packages) == 0 { + // Get all custom packages + customPackages, err = getPackages(ctx, kubeClient, idpbuilderNamespace) + if err != nil { + return fmt.Errorf("listing custom packages: %w", err) + } + } else { + // Get the custom package using its name + customPackages := v1alpha1.CustomPackageList{} + for _, name := range packages { + cp, err := getPackageByName(ctx, kubeClient, idpbuilderNamespace, name) + if err != nil { + return fmt.Errorf("get custom package: %w", err) + } + customPackages.Items = append(customPackages.Items, cp) + } + } + + for _, cp := range customPackages.Items { + newPackage := entity.Package{} + newPackage.Name = cp.Name + newPackage.Namespace = cp.Namespace + // There is a GitRepositoryRefs when the project has been cloned to the internal git repository + if cp.Status.GitRepositoryRefs != nil { + newPackage.GitRepository = cp.Spec.InternalGitServeURL + "/" + v1alpha1.GiteaAdminUserName + "/" + idpbuilderNamespace + "-" + cp.Status.GitRepositoryRefs[0].Name + } else { + ref := "main" + if cp.Spec.RemoteRepository.Ref != "" { + ref = cp.Spec.RemoteRepository.Ref + } + newPackage.GitRepository = cp.Spec.RemoteRepository.Url + "/tree/" + ref + "/" + cp.Spec.RemoteRepository.Path + } + packageList = append(packageList, newPackage) + } + + packagePrinter := printer.PackagePrinter{ + Packages: packageList, + OutWriter: outWriter, + } + return packagePrinter.PrintOutput(format) +} + +func getPackageByName(ctx context.Context, kubeClient client.Client, ns, name string) (v1alpha1.CustomPackage, error) { + p := v1alpha1.CustomPackage{} + return p, kubeClient.Get(ctx, client.ObjectKey{Name: name, Namespace: ns}, &p) +} + +func getIDPNamespace(ctx context.Context, kubeClient client.Client) (string, error) { + build, err := getLocalBuild(ctx, kubeClient) + if err != nil { + return "", err + } + // TODO: We assume that only one LocalBuild has been created for one cluster ! + idpNamespace := v1alpha1.FieldManager + "-" + build.Items[0].Name + return idpNamespace, nil +} + +func getLocalBuild(ctx context.Context, kubeClient client.Client) (v1alpha1.LocalbuildList, error) { + localBuildList := v1alpha1.LocalbuildList{} + return localBuildList, kubeClient.List(ctx, &localBuildList) +} + +func getPackages(ctx context.Context, kubeClient client.Client, ns string) (v1alpha1.CustomPackageList, error) { + packageList := v1alpha1.CustomPackageList{} + return packageList, kubeClient.List(ctx, &packageList, client.InNamespace(ns)) +} diff --git a/pkg/cmd/get/root.go b/pkg/cmd/get/root.go index 0bd62036..46a0d3cb 100644 --- a/pkg/cmd/get/root.go +++ b/pkg/cmd/get/root.go @@ -21,6 +21,7 @@ var ( func init() { GetCmd.AddCommand(ClustersCmd) GetCmd.AddCommand(SecretsCmd) + GetCmd.AddCommand(PackagesCmd) GetCmd.PersistentFlags().StringSliceVarP(&packages, "packages", "p", []string{}, "names of packages.") GetCmd.PersistentFlags().StringVarP(&outputFormat, "output", "o", "table", "Output format: table (default if not specified), json or yaml.") GetCmd.PersistentFlags().StringVarP(&helpers.KubeConfigPath, "kubeconfig", "", "", "kube config file Path.") diff --git a/pkg/entity/package.go b/pkg/entity/package.go new file mode 100644 index 00000000..41c9320c --- /dev/null +++ b/pkg/entity/package.go @@ -0,0 +1,8 @@ +package entity + +type Package struct { + Name string + Namespace string + Type string + GitRepository string +} diff --git a/pkg/printer/package.go b/pkg/printer/package.go new file mode 100644 index 00000000..38f19be7 --- /dev/null +++ b/pkg/printer/package.go @@ -0,0 +1,46 @@ +package printer + +import ( + "fmt" + "github.com/cnoe-io/idpbuilder/pkg/entity" + "io" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type PackagePrinter struct { + Packages []entity.Package + OutWriter io.Writer +} + +func (pp PackagePrinter) PrintOutput(format string) error { + switch format { + case "json": + return PrintDataAsJson(pp.Packages, pp.OutWriter) + case "yaml": + return PrintDataAsYaml(pp.Packages, pp.OutWriter) + case "table": + return PrintDataAsTable(generatePackageTable(pp.Packages), pp.OutWriter) + default: + return fmt.Errorf("output format %s is not supported", format) + } +} + +func generatePackageTable(packagesTable []entity.Package) metav1.Table { + table := &metav1.Table{} + table.ColumnDefinitions = []metav1.TableColumnDefinition{ + {Name: "Name", Type: "string"}, + {Name: "Namespace", Type: "string"}, + {Name: "GitRepository", Type: "string"}, + } + for _, p := range packagesTable { + row := metav1.TableRow{ + Cells: []interface{}{ + p.Name, + p.Namespace, + p.GitRepository, + }, + } + table.Rows = append(table.Rows, row) + } + return *table +}