diff --git a/pkg/cmd/get/clusters.go b/pkg/cmd/get/clusters.go index 22a13be2..95b94fdf 100644 --- a/pkg/cmd/get/clusters.go +++ b/pkg/cmd/get/clusters.go @@ -5,10 +5,10 @@ import ( "fmt" "github.com/cnoe-io/idpbuilder/api/v1alpha1" "github.com/cnoe-io/idpbuilder/pkg/cmd/helpers" - "github.com/cnoe-io/idpbuilder/pkg/entity" "github.com/cnoe-io/idpbuilder/pkg/k8s" "github.com/cnoe-io/idpbuilder/pkg/kind" "github.com/cnoe-io/idpbuilder/pkg/printer" + idpTypes "github.com/cnoe-io/idpbuilder/pkg/printer/types" "github.com/cnoe-io/idpbuilder/pkg/util" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" @@ -55,7 +55,7 @@ func list(cmd *cobra.Command, args []string) error { } } -func populateClusterList() ([]entity.Cluster, error) { +func populateClusterList() ([]idpTypes.Cluster, error) { logger := helpers.CmdLogger detectOpt, err := util.DetectKindNodeProvider() @@ -81,7 +81,7 @@ func populateClusterList() ([]entity.Cluster, error) { } // Create an empty array of clusters to collect the information - clusterList := []entity.Cluster{} + clusterList := []idpTypes.Cluster{} // List the idp builder clusters according to the provider: podman or docker provider := cluster.NewProvider(cluster.ProviderWithLogger(kind.KindLoggerFromLogr(&logger)), detectOpt) @@ -97,7 +97,7 @@ func populateClusterList() ([]entity.Cluster, error) { } for _, cluster := range clusters { - aCluster := entity.Cluster{Name: cluster} + aCluster := idpTypes.Cluster{Name: cluster} // Search about the idp cluster within the kubeconfig file and show information c, found := findClusterByName(config, "kind-"+cluster) @@ -139,7 +139,7 @@ func populateClusterList() ([]entity.Cluster, error) { for _, node := range nodeList.Items { nodeName := node.Name - aNode := entity.Node{} + aNode := idpTypes.Node{} aNode.Name = nodeName for _, addr := range node.Status.Addresses { @@ -158,7 +158,7 @@ func populateClusterList() ([]entity.Cluster, error) { cpu := resources[corev1.ResourceCPU] pods := resources[corev1.ResourcePods] - aNode.Capacity = entity.Capacity{ + aNode.Capacity = idpTypes.Capacity{ Memory: float64(memory.Value()) / (1024 * 1024 * 1024), Cpu: cpu.Value(), Pods: pods.Value(), @@ -181,11 +181,11 @@ func populateClusterList() ([]entity.Cluster, error) { return clusterList, nil } -func printAllocatedResources(ctx context.Context, k8sClient client.Client, nodeName string) (entity.Allocated, error) { +func printAllocatedResources(ctx context.Context, k8sClient client.Client, nodeName string) (idpTypes.Allocated, error) { // List all pods on the specified node var podList corev1.PodList if err := k8sClient.List(ctx, &podList, client.MatchingFields{"spec.nodeName": nodeName}); err != nil { - return entity.Allocated{}, fmt.Errorf("failed to list pods on node %s.", nodeName) + return idpTypes.Allocated{}, fmt.Errorf("failed to list pods on node %s.", nodeName) } // Initialize counters for CPU and memory requests @@ -204,7 +204,7 @@ func printAllocatedResources(ctx context.Context, k8sClient client.Client, nodeN } } - allocated := entity.Allocated{ + allocated := idpTypes.Allocated{ Memory: totalMemory.String(), Cpu: totalCPU.String(), } diff --git a/pkg/cmd/get/packages.go b/pkg/cmd/get/packages.go new file mode 100644 index 00000000..b42f11d6 --- /dev/null +++ b/pkg/cmd/get/packages.go @@ -0,0 +1,141 @@ +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/k8s" + "github.com/cnoe-io/idpbuilder/pkg/printer" + "github.com/cnoe-io/idpbuilder/pkg/printer/types" + "github.com/cnoe-io/idpbuilder/pkg/util" + "github.com/spf13/cobra" + "io" + "k8s.io/client-go/util/homedir" + "os" + "path/filepath" + "sigs.k8s.io/controller-runtime/pkg/client" + "strconv" +) + +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, + TemplateData: v1alpha1.BuildCustomizationSpec{}, + } + + 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 := []types.Package{} + customPackages := v1alpha1.CustomPackageList{} + var err error + + idpbuilderNamespace, err := getIDPNamespace(ctx, kubeClient) + if err != nil { + return fmt.Errorf("getting namespace: %w", err) + } + + argocdBaseUrl, err := util.ArgocdBaseUrl(ctx) + if err != nil { + return fmt.Errorf("Error creating argocd Url: %v\n", 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 + for _, name := range packages { + cp, err := getPackageByName(ctx, kubeClient, idpbuilderNamespace, name) + if err != nil { + return fmt.Errorf("getting custom package %s: %w", name, err) + } + customPackages.Items = append(customPackages.Items, cp) + } + } + + for _, cp := range customPackages.Items { + newPackage := types.Package{} + newPackage.Name = cp.Name + newPackage.Namespace = cp.Namespace + newPackage.ArgocdRepository = argocdBaseUrl + "/applications/" + cp.Spec.ArgoCD.Namespace + "/" + cp.Spec.ArgoCD.Name + // 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 { + // Default branch reference + ref := "main" + if cp.Spec.RemoteRepository.Ref != "" { + ref = cp.Spec.RemoteRepository.Ref + } + newPackage.GitRepository = cp.Spec.RemoteRepository.Url + "/tree/" + ref + "/" + cp.Spec.RemoteRepository.Path + } + + newPackage.Status = strconv.FormatBool(cp.Status.Synced) + + 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/cmd/get/secrets.go b/pkg/cmd/get/secrets.go index 1f15bc06..8506bcd5 100644 --- a/pkg/cmd/get/secrets.go +++ b/pkg/cmd/get/secrets.go @@ -3,25 +3,21 @@ package get import ( "context" "fmt" - "io" - "os" - "path/filepath" - "strings" - - "github.com/cnoe-io/idpbuilder/pkg/entity" - "github.com/cnoe-io/idpbuilder/pkg/printer" - "github.com/cnoe-io/idpbuilder/pkg/util" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/cnoe-io/idpbuilder/api/v1alpha1" "github.com/cnoe-io/idpbuilder/pkg/build" "github.com/cnoe-io/idpbuilder/pkg/k8s" + "github.com/cnoe-io/idpbuilder/pkg/printer" + "github.com/cnoe-io/idpbuilder/pkg/printer/types" + "github.com/cnoe-io/idpbuilder/pkg/util" "github.com/spf13/cobra" + "io" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" "k8s.io/client-go/util/homedir" + "os" + "path/filepath" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -79,7 +75,7 @@ func getSecretsE(cmd *cobra.Command, args []string) error { func printAllPackageSecrets(ctx context.Context, outWriter io.Writer, kubeClient client.Client, format string) error { selector := labels.NewSelector() - secrets := []entity.Secret{} + secrets := []types.Secret{} secretPrinter := printer.SecretPrinter{ Secrets: secrets, OutWriter: outWriter, @@ -118,7 +114,7 @@ func printAllPackageSecrets(ctx context.Context, outWriter io.Writer, kubeClient func printPackageSecrets(ctx context.Context, outWriter io.Writer, kubeClient client.Client, format string) error { selector := labels.NewSelector() - secrets := []entity.Secret{} + secrets := []types.Secret{} secretPrinter := printer.SecretPrinter{ OutWriter: outWriter, } @@ -166,42 +162,8 @@ func printPackageSecrets(ctx context.Context, outWriter io.Writer, kubeClient cl return secretPrinter.PrintOutput(format) } -func generateSecretTable(secretTable []entity.Secret) metav1.Table { - table := &metav1.Table{} - table.ColumnDefinitions = []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string"}, - {Name: "Namespace", Type: "string"}, - {Name: "Username", Type: "string"}, - {Name: "Password", Type: "string"}, - {Name: "Token", Type: "string"}, - {Name: "Data", Type: "string"}, - } - for _, secret := range secretTable { - var dataEntries []string - - if !secret.IsCore { - for key, value := range secret.Data { - dataEntries = append(dataEntries, fmt.Sprintf("%s=%s", key, value)) - } - } - dataString := strings.Join(dataEntries, ", ") - row := metav1.TableRow{ - Cells: []interface{}{ - secret.Name, - secret.Namespace, - secret.Username, - secret.Password, - secret.Token, - dataString, - }, - } - table.Rows = append(table.Rows, row) - } - return *table -} - -func populateSecret(s v1.Secret, isCoreSecret bool) entity.Secret { - secret := entity.Secret{ +func populateSecret(s v1.Secret, isCoreSecret bool) types.Secret { + secret := types.Secret{ Name: s.Name, Namespace: s.Namespace, } diff --git a/pkg/cmd/get/secrets_test.go b/pkg/cmd/get/secrets_test.go index 07842c1c..042de390 100644 --- a/pkg/cmd/get/secrets_test.go +++ b/pkg/cmd/get/secrets_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/cnoe-io/idpbuilder/api/v1alpha1" - "github.com/cnoe-io/idpbuilder/pkg/entity" + "github.com/cnoe-io/idpbuilder/pkg/printer/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" v1 "k8s.io/api/core/v1" @@ -145,7 +145,7 @@ func TestOutput(t *testing.T) { ctx := context.Background() r, _ := labels.NewRequirement(v1alpha1.CLISecretLabelKey, selection.Equals, []string{v1alpha1.CLISecretLabelValue}) - corePkgData := map[string]entity.Secret{ + corePkgData := map[string]types.Secret{ argoCDInitialAdminSecretName: { IsCore: true, Name: argoCDInitialAdminSecretName, @@ -162,7 +162,7 @@ func TestOutput(t *testing.T) { }, } - packageData := map[string]entity.Secret{ + packageData := map[string]types.Secret{ "name1": { Name: "name1", Namespace: "ns1", @@ -216,7 +216,7 @@ func TestOutput(t *testing.T) { assert.Nil(t, err) // verify received json data - var received []entity.Secret + var received []types.Secret err = json.Unmarshal(buffer.Bytes(), &received) assert.Nil(t, err) assert.Equal(t, 4, len(received)) @@ -244,7 +244,7 @@ func TestOutput(t *testing.T) { assert.Equal(t, 0, len(packageData)) } -func secretDataToSecret(data entity.Secret) v1.Secret { +func secretDataToSecret(data types.Secret) v1.Secret { d := make(map[string][]byte) if data.IsCore { d["username"] = []byte(data.Username) diff --git a/pkg/controllers/crd.go b/pkg/controllers/crd.go index ca7e2771..9f4d5a05 100644 --- a/pkg/controllers/crd.go +++ b/pkg/controllers/crd.go @@ -4,10 +4,10 @@ import ( "context" "embed" "fmt" + "github.com/cnoe-io/idpbuilder/pkg/util/fs" "time" "github.com/cnoe-io/idpbuilder/pkg/k8s" - "github.com/cnoe-io/idpbuilder/pkg/util" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -20,7 +20,7 @@ import ( var crdFS embed.FS func getK8sResources(scheme *runtime.Scheme, templateData any) ([]client.Object, error) { - rawResources, err := util.ConvertFSToBytes(crdFS, "resources", templateData) + rawResources, err := fs.ConvertFSToBytes(crdFS, "resources", templateData) if err != nil { return nil, err } diff --git a/pkg/controllers/gitrepository/gitea.go b/pkg/controllers/gitrepository/gitea.go index a19a433f..68b93a4a 100644 --- a/pkg/controllers/gitrepository/gitea.go +++ b/pkg/controllers/gitrepository/gitea.go @@ -3,6 +3,7 @@ package gitrepository import ( "context" "fmt" + "github.com/cnoe-io/idpbuilder/pkg/util/files" "os" "path/filepath" @@ -136,7 +137,7 @@ func writeRepoContents(repo *v1alpha1.GitRepository, dstPath string, config v1al return nil } - err := util.CopyDirectory(repo.Spec.Source.Path, dstPath) + err := files.CopyDirectory(repo.Spec.Source.Path, dstPath) if err != nil { return fmt.Errorf("copying files: %w", err) } diff --git a/pkg/controllers/localbuild/argo_test.go b/pkg/controllers/localbuild/argo_test.go index abad74b6..ea0d97b0 100644 --- a/pkg/controllers/localbuild/argo_test.go +++ b/pkg/controllers/localbuild/argo_test.go @@ -2,13 +2,13 @@ package localbuild import ( "context" + "github.com/cnoe-io/idpbuilder/pkg/util/fs" "testing" argov1alpha1 "github.com/cnoe-io/argocd-api/api/argo/application/v1alpha1" "github.com/cnoe-io/idpbuilder/api/v1alpha1" "github.com/cnoe-io/idpbuilder/globals" "github.com/cnoe-io/idpbuilder/pkg/k8s" - "github.com/cnoe-io/idpbuilder/pkg/util" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -43,7 +43,7 @@ func TestGetRawInstallResources(t *testing.T) { resourceFS: installArgoFS, resourcePath: "resources/argo", } - resources, err := util.ConvertFSToBytes(e.resourceFS, e.resourcePath, + resources, err := fs.ConvertFSToBytes(e.resourceFS, e.resourcePath, v1alpha1.BuildCustomizationSpec{ Protocol: "", Host: "", diff --git a/pkg/controllers/localbuild/controller.go b/pkg/controllers/localbuild/controller.go index 0f21d5e8..ca785c01 100644 --- a/pkg/controllers/localbuild/controller.go +++ b/pkg/controllers/localbuild/controller.go @@ -693,7 +693,12 @@ func (r *LocalbuildReconciler) extractGiteaAdminSecret(ctx context.Context) (str } func (r *LocalbuildReconciler) updateGiteaPassword(ctx context.Context, adminPassword string) error { - client, err := gitea.NewClient(util.GiteaBaseUrl(r.Config), gitea.SetHTTPClient(util.GetHttpClient()), + giteaBaseUrl, err := util.GiteaBaseUrl(ctx) + if err != nil { + return fmt.Errorf("generating gitea url: %w", err) + } + + client, err := gitea.NewClient(giteaBaseUrl, gitea.SetHTTPClient(util.GetHttpClient()), gitea.SetBasicAuth("giteaAdmin", adminPassword), gitea.SetContext(ctx), ) if err != nil { @@ -718,7 +723,12 @@ func (r *LocalbuildReconciler) updateGiteaPassword(ctx context.Context, adminPas } func (r *LocalbuildReconciler) updateArgocdPassword(ctx context.Context, adminPassword string) error { - argocdEndpoint := util.ArgocdBaseUrl(r.Config) + "/api/v1" + argocdBaseUrl, err := util.ArgocdBaseUrl(ctx) + if err != nil { + return fmt.Errorf("Error creating argocd Url: %v\n", err) + } + + argocdEndpoint := argocdBaseUrl + "/api/v1" payload := map[string]string{ "username": "admin", diff --git a/pkg/controllers/localbuild/gitea.go b/pkg/controllers/localbuild/gitea.go index 83c75f30..b83c2de9 100644 --- a/pkg/controllers/localbuild/gitea.go +++ b/pkg/controllers/localbuild/gitea.go @@ -5,10 +5,10 @@ import ( "embed" "encoding/base64" "fmt" + "github.com/cnoe-io/idpbuilder/pkg/k8s" "net/http" "github.com/cnoe-io/idpbuilder/api/v1alpha1" - "github.com/cnoe-io/idpbuilder/pkg/k8s" "github.com/cnoe-io/idpbuilder/pkg/util" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -86,7 +86,11 @@ func (r *LocalbuildReconciler) ReconcileGitea(ctx context.Context, req ctrl.Requ return result, err } - baseUrl := util.GiteaBaseUrl(r.Config) + baseUrl, err := util.GiteaBaseUrl(ctx) + if err != nil { + return ctrl.Result{}, err + } + // need this to ensure gitrepository controller can reach the api endpoint. logger.V(1).Info("checking gitea api endpoint", "url", baseUrl) c := util.GetHttpClient() diff --git a/pkg/entity/allocated.go b/pkg/entity/allocated.go deleted file mode 100644 index 297f024b..00000000 --- a/pkg/entity/allocated.go +++ /dev/null @@ -1,6 +0,0 @@ -package entity - -type Allocated struct { - Cpu string - Memory string -} diff --git a/pkg/entity/capacity.go b/pkg/entity/capacity.go deleted file mode 100644 index cbe910dd..00000000 --- a/pkg/entity/capacity.go +++ /dev/null @@ -1,7 +0,0 @@ -package entity - -type Capacity struct { - Memory float64 - Pods int64 - Cpu int64 -} diff --git a/pkg/entity/cluster.go b/pkg/entity/cluster.go deleted file mode 100644 index 582e29c0..00000000 --- a/pkg/entity/cluster.go +++ /dev/null @@ -1,10 +0,0 @@ -package entity - -type Cluster struct { - Name string - URLKubeApi string - KubePort int32 - TlsCheck bool - ExternalPort int32 - Nodes []Node -} diff --git a/pkg/entity/node.go b/pkg/entity/node.go deleted file mode 100644 index 7d07d5a6..00000000 --- a/pkg/entity/node.go +++ /dev/null @@ -1,9 +0,0 @@ -package entity - -type Node struct { - Name string - InternalIP string - ExternalIP string - Capacity Capacity - Allocated Allocated -} diff --git a/pkg/entity/secret.go b/pkg/entity/secret.go deleted file mode 100644 index f7c2b53a..00000000 --- a/pkg/entity/secret.go +++ /dev/null @@ -1,11 +0,0 @@ -package entity - -type Secret struct { - IsCore bool - Name string `json:"name"` - Namespace string `json:"namespace"` - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - Token string `json:"token,omitempty"` - Data map[string]string `json:"data,omitempty"` -} diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index b033887f..066b5e00 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -3,15 +3,25 @@ package k8s import ( "context" "fmt" - corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/util/homedir" + "path/filepath" "sigs.k8s.io/controller-runtime/pkg/client" ) +func GetKubeClient() (client.Client, error) { + conf, err := clientcmd.BuildConfigFromFlags("", filepath.Join(homedir.HomeDir(), ".kube", "config")) + if err != nil { + return nil, err + } + return client.New(conf, client.Options{Scheme: GetScheme()}) +} + func EnsureObject(ctx context.Context, kubeClient client.Client, obj client.Object, namespace string) error { curObj := &unstructured.Unstructured{} curObj.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind()) diff --git a/pkg/k8s/util.go b/pkg/k8s/util.go index 68b5366d..2ec6984a 100644 --- a/pkg/k8s/util.go +++ b/pkg/k8s/util.go @@ -2,14 +2,15 @@ package k8s import ( "embed" - "github.com/cnoe-io/idpbuilder/pkg/util" + "github.com/cnoe-io/idpbuilder/pkg/util/files" + "github.com/cnoe-io/idpbuilder/pkg/util/fs" "k8s.io/apimachinery/pkg/runtime" "os" "sigs.k8s.io/controller-runtime/pkg/client" ) func BuildCustomizedManifests(filePath, fsPath string, resourceFS embed.FS, scheme *runtime.Scheme, templateData any) ([][]byte, error) { - rawResources, err := util.ConvertFSToBytes(resourceFS, fsPath, templateData) + rawResources, err := fs.ConvertFSToBytes(resourceFS, fsPath, templateData) if err != nil { return nil, err } @@ -27,7 +28,7 @@ func BuildCustomizedManifests(filePath, fsPath string, resourceFS embed.FS, sche } func BuildCustomizedObjects(filePath, fsPath string, resourceFS embed.FS, scheme *runtime.Scheme, templateData any) ([]client.Object, error) { - rawResources, err := util.ConvertFSToBytes(resourceFS, fsPath, templateData) + rawResources, err := fs.ConvertFSToBytes(resourceFS, fsPath, templateData) if err != nil { return nil, err } @@ -50,7 +51,7 @@ func applyOverrides(filePath string, originalFiles [][]byte, scheme *runtime.Sch return nil, nil, err } - rendered, err := util.ApplyTemplate(customBS, templateData) + rendered, err := files.ApplyTemplate(customBS, templateData) if err != nil { return nil, nil, err } diff --git a/pkg/kind/cluster.go b/pkg/kind/cluster.go index 42e3abb3..3aa1403b 100644 --- a/pkg/kind/cluster.go +++ b/pkg/kind/cluster.go @@ -5,13 +5,14 @@ import ( "embed" "errors" "fmt" + "github.com/cnoe-io/idpbuilder/pkg/util" + "github.com/cnoe-io/idpbuilder/pkg/util/files" "io/fs" "os" "strconv" "strings" "github.com/cnoe-io/idpbuilder/api/v1alpha1" - "github.com/cnoe-io/idpbuilder/pkg/util" "github.com/go-logr/logr" "sigs.k8s.io/controller-runtime/pkg/log" kindv1alpha4 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" @@ -94,7 +95,7 @@ func (c *Cluster) getConfig() ([]byte, error) { } var retBuff []byte - if retBuff, err = util.ApplyTemplate(rawConfigTempl, TemplateConfig{ + if retBuff, err = files.ApplyTemplate(rawConfigTempl, TemplateConfig{ BuildCustomizationSpec: c.cfg, KubernetesVersion: c.kubeVersion, ExtraPortsMapping: portMappingPairs, diff --git a/pkg/printer/cluster.go b/pkg/printer/cluster.go index 4ebd4c55..9e412271 100644 --- a/pkg/printer/cluster.go +++ b/pkg/printer/cluster.go @@ -2,13 +2,13 @@ package printer import ( "fmt" - "github.com/cnoe-io/idpbuilder/pkg/entity" + "github.com/cnoe-io/idpbuilder/pkg/printer/types" "io" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) type ClusterPrinter struct { - Clusters []entity.Cluster + Clusters []types.Cluster OutWriter io.Writer } @@ -25,7 +25,7 @@ func (cp ClusterPrinter) PrintOutput(format string) error { } } -func generateClusterTable(input []entity.Cluster) metav1.Table { +func generateClusterTable(input []types.Cluster) metav1.Table { table := &metav1.Table{} table.ColumnDefinitions = []metav1.TableColumnDefinition{ {Name: "Name", Type: "string"}, @@ -52,7 +52,7 @@ func generateClusterTable(input []entity.Cluster) metav1.Table { return *table } -func generateNodeData(nodes []entity.Node) string { +func generateNodeData(nodes []types.Node) string { var result string for i, aNode := range nodes { result += aNode.Name diff --git a/pkg/printer/package.go b/pkg/printer/package.go new file mode 100644 index 00000000..73c4e7cb --- /dev/null +++ b/pkg/printer/package.go @@ -0,0 +1,50 @@ +package printer + +import ( + "fmt" + "github.com/cnoe-io/idpbuilder/pkg/printer/types" + "io" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type PackagePrinter struct { + Packages []types.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 []types.Package) metav1.Table { + table := &metav1.Table{} + table.ColumnDefinitions = []metav1.TableColumnDefinition{ + {Name: "Name", Type: "string"}, + {Name: "idp namespace", Type: "string"}, + {Name: "Git Repository", Type: "string"}, + {Name: "Argocd Url", Type: "string"}, + {Name: "Status", Type: "string"}, + } + for _, p := range packagesTable { + row := metav1.TableRow{ + Cells: []interface{}{ + p.Name, + p.Namespace, + p.GitRepository, + p.ArgocdRepository, + p.Status, + }, + } + table.Rows = append(table.Rows, row) + } + return *table +} diff --git a/pkg/printer/secret.go b/pkg/printer/secret.go index 425f961d..a2417d82 100644 --- a/pkg/printer/secret.go +++ b/pkg/printer/secret.go @@ -2,14 +2,14 @@ package printer import ( "fmt" - "github.com/cnoe-io/idpbuilder/pkg/entity" + "github.com/cnoe-io/idpbuilder/pkg/printer/types" "io" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "strings" ) type SecretPrinter struct { - Secrets []entity.Secret + Secrets []types.Secret OutWriter io.Writer } @@ -26,7 +26,7 @@ func (sp SecretPrinter) PrintOutput(format string) error { } } -func generateSecretTable(secretTable []entity.Secret) metav1.Table { +func generateSecretTable(secretTable []types.Secret) metav1.Table { table := &metav1.Table{} table.ColumnDefinitions = []metav1.TableColumnDefinition{ {Name: "Name", Type: "string"}, diff --git a/pkg/printer/types/internal_types.go b/pkg/printer/types/internal_types.go new file mode 100644 index 00000000..3831cfc8 --- /dev/null +++ b/pkg/printer/types/internal_types.go @@ -0,0 +1,50 @@ +package types + +// Types used internally to define the objects needed to print data, etc + +type Allocated struct { + Cpu string + Memory string +} + +type Capacity struct { + Memory float64 + Pods int64 + Cpu int64 +} + +type Cluster struct { + Name string + URLKubeApi string + KubePort int32 + TlsCheck bool + ExternalPort int32 + Nodes []Node +} + +type Node struct { + Name string + InternalIP string + ExternalIP string + Capacity Capacity + Allocated Allocated +} + +type Package struct { + Name string + Namespace string + Type string + GitRepository string + ArgocdRepository string + Status string +} + +type Secret struct { + IsCore bool + Name string `json:"name"` + Namespace string `json:"namespace"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Token string `json:"token,omitempty"` + Data map[string]string `json:"data,omitempty"` +} diff --git a/pkg/util/argocd.go b/pkg/util/argocd.go index 91700d8f..34477613 100644 --- a/pkg/util/argocd.go +++ b/pkg/util/argocd.go @@ -1,8 +1,9 @@ package util import ( + "context" "fmt" - "github.com/cnoe-io/idpbuilder/api/v1alpha1" + "github.com/cnoe-io/idpbuilder/pkg/util/idp" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -14,8 +15,12 @@ const ( ArgocdIngressURL = "%s://argocd.cnoe.localtest.me:%s" ) -func ArgocdBaseUrl(config v1alpha1.BuildCustomizationSpec) string { - return fmt.Sprintf(ArgocdIngressURL, config.Protocol, config.Port) +func ArgocdBaseUrl(ctx context.Context) (string, error) { + idpConfig, err := idp.GetConfig(ctx) + if err != nil { + return "", fmt.Errorf("error fetching idp config: %s", err) + } + return fmt.Sprintf(ArgocdIngressURL, idpConfig.Protocol, idpConfig.Port), nil } func ArgocdInitialAdminSecretObject() corev1.Secret { diff --git a/pkg/util/files.go b/pkg/util/files/files.go similarity index 99% rename from pkg/util/files.go rename to pkg/util/files/files.go index 5514a978..6c2e1b06 100644 --- a/pkg/util/files.go +++ b/pkg/util/files/files.go @@ -1,4 +1,4 @@ -package util +package files import ( "bytes" diff --git a/pkg/util/fs.go b/pkg/util/fs/fs.go similarity index 93% rename from pkg/util/fs.go rename to pkg/util/fs/fs.go index d7dcba3c..4fffbe8f 100644 --- a/pkg/util/fs.go +++ b/pkg/util/fs/fs.go @@ -1,8 +1,9 @@ -package util +package fs import ( "errors" "fmt" + "github.com/cnoe-io/idpbuilder/pkg/util/files" "io" "io/fs" "os" @@ -29,7 +30,7 @@ func ConvertFSToBytes(inFS FS, name string, templateData any) ([][]byte, error) return nil, err } - if returnedRawResource, err := ApplyTemplate(rawResource, templateData); err == nil { + if returnedRawResource, err := files.ApplyTemplate(rawResource, templateData); err == nil { rawResources = append(rawResources, returnedRawResource) } else { return nil, err diff --git a/pkg/util/fs_test.go b/pkg/util/fs/fs_test.go similarity index 99% rename from pkg/util/fs_test.go rename to pkg/util/fs/fs_test.go index da0a692e..c37de94f 100644 --- a/pkg/util/fs_test.go +++ b/pkg/util/fs/fs_test.go @@ -1,4 +1,4 @@ -package util +package fs import ( "fmt" diff --git a/pkg/util/gitea.go b/pkg/util/gitea.go index 43dda037..62415c23 100644 --- a/pkg/util/gitea.go +++ b/pkg/util/gitea.go @@ -6,6 +6,7 @@ import ( "encoding/base64" "fmt" "github.com/cnoe-io/idpbuilder/api/v1alpha1" + "github.com/cnoe-io/idpbuilder/pkg/util/idp" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -57,7 +58,12 @@ func PatchPasswordSecret(ctx context.Context, kubeClient client.Client, config v if strings.Contains(secretName, "gitea") { // We should recreate a token as user/password changed - t, err := GetGiteaToken(ctx, GiteaBaseUrl(config), string(username), string(pass)) + giteaUrl, err := GiteaBaseUrl(ctx) + if err != nil { + return fmt.Errorf("getting giteaurl: %w", err) + } + + t, err := GetGiteaToken(ctx, giteaUrl, string(username), string(pass)) if err != nil { return fmt.Errorf("getting gitea token: %w", err) } @@ -107,6 +113,10 @@ func GetGiteaToken(ctx context.Context, baseUrl, username, password string) (str return token.Token, nil } -func GiteaBaseUrl(config v1alpha1.BuildCustomizationSpec) string { - return fmt.Sprintf(GiteaIngressURL, config.Protocol, config.Port) +func GiteaBaseUrl(ctx context.Context) (string, error) { + idpConfig, err := idp.GetConfig(ctx) + if err != nil { + return "", fmt.Errorf("error fetching idp config: %s", err) + } + return fmt.Sprintf(GiteaIngressURL, idpConfig.Protocol, idpConfig.Port), nil } diff --git a/pkg/util/idp/idp.go b/pkg/util/idp/idp.go new file mode 100644 index 00000000..10c7b405 --- /dev/null +++ b/pkg/util/idp/idp.go @@ -0,0 +1,30 @@ +package idp + +import ( + "context" + "github.com/cnoe-io/idpbuilder/api/v1alpha1" + "github.com/cnoe-io/idpbuilder/pkg/k8s" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func GetConfig(ctx context.Context) (v1alpha1.BuildCustomizationSpec, error) { + b := v1alpha1.BuildCustomizationSpec{} + + kubeClient, err := k8s.GetKubeClient() + if err != nil { + return b, err + } + + list, err := getLocalBuild(ctx, kubeClient) + if err != nil { + return b, err + } + + // TODO: We assume that only one LocalBuild exists ! + return list.Items[0].Spec.BuildCustomization, nil +} + +func getLocalBuild(ctx context.Context, kubeClient client.Client) (v1alpha1.LocalbuildList, error) { + localBuildList := v1alpha1.LocalbuildList{} + return localBuildList, kubeClient.List(ctx, &localBuildList) +}