Skip to content

Commit

Permalink
OCM-6527 | feat: add describe ingress command
Browse files Browse the repository at this point in the history
  • Loading branch information
gdbranco committed Mar 13, 2024
1 parent 4b55e57 commit 1041130
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 35 deletions.
23 changes: 14 additions & 9 deletions cmd/describe/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/openshift/rosa/cmd/describe/addon"
"github.com/openshift/rosa/cmd/describe/admin"
"github.com/openshift/rosa/cmd/describe/cluster"
"github.com/openshift/rosa/cmd/describe/ingress"
"github.com/openshift/rosa/cmd/describe/installation"
"github.com/openshift/rosa/cmd/describe/kubeletconfig"
"github.com/openshift/rosa/cmd/describe/machinepool"
Expand All @@ -39,17 +40,21 @@ var Cmd = &cobra.Command{
}

func init() {
Cmd.AddCommand(addon.Cmd)
Cmd.AddCommand(admin.Cmd)
Cmd.AddCommand(cluster.Cmd)
Cmd.AddCommand(service.Cmd)
Cmd.AddCommand(installation.Cmd)
Cmd.AddCommand(upgrade.Cmd)
Cmd.AddCommand(tuningconfigs.Cmd)
Cmd.AddCommand(machinepool.Cmd)
Cmd.AddCommand(kubeletconfig.Cmd)
cmds := []*cobra.Command{
addon.Cmd, admin.Cmd, cluster.Cmd, service.Cmd,
installation.Cmd, upgrade.Cmd, tuningconfigs.Cmd,
machinepool.Cmd, kubeletconfig.Cmd, ingress.Cmd,
}
for _, cmd := range cmds {
Cmd.AddCommand(cmd)
}

flags := Cmd.PersistentFlags()
arguments.AddProfileFlag(flags)
arguments.AddRegionFlag(flags)

globallyAvailableCommands := []*cobra.Command{
ingress.Cmd,
}
arguments.MarkRegionHidden(Cmd, globallyAvailableCommands)
}
165 changes: 165 additions & 0 deletions cmd/describe/ingress/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package ingress

import (
"bytes"
"encoding/json"
"fmt"
"os"
"regexp"
"sort"
"strconv"
"strings"

cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
"github.com/spf13/cobra"

"github.com/openshift/rosa/pkg/helper"
"github.com/openshift/rosa/pkg/ocm"
"github.com/openshift/rosa/pkg/output"
"github.com/openshift/rosa/pkg/rosa"
)

// Regular expression to used to make sure that the identifier given by the
// user is safe and that it there is no risk of SQL injection:
var ingressKeyRE = regexp.MustCompile(`^[a-z0-9]{3,5}$`)

var Cmd = &cobra.Command{
Use: "ingress",
Short: "Show details of the specified ingress within cluster",
Example: `rosa describe ingress <ingress_id> -c mycluster`,
Run: run,
Args: func(_ *cobra.Command, argv []string) error {
if len(argv) != 1 {
return fmt.Errorf(
"Expected exactly one command line parameter containing the id of the ingress",
)
}
return nil
},
}

func init() {
ocm.AddClusterFlag(Cmd)
output.AddFlag(Cmd)
}

func run(_ *cobra.Command, argv []string) {
r := rosa.NewRuntime().WithOCM()
defer r.Cleanup()

ingressKey := argv[0]
if !ingressKeyRE.MatchString(ingressKey) {
r.Reporter.Errorf(
"Ingress identifier '%s' isn't valid: it must contain only letters or digits",
ingressKey,
)
os.Exit(1)
}

cluster := r.FetchCluster()

ingress, err := r.OCMClient.GetIngress(cluster.ID(), ingressKey)
if err != nil {
r.Reporter.Errorf("Failed to fetch ingress: %v", err)
os.Exit(1)
}
if output.HasFlag() {
var b bytes.Buffer
err := cmv1.MarshalIngress(ingress, &b)
if err != nil {
r.Reporter.Errorf("Failed to generate output for ingress '%s': %v", ingress.ID(), err)
os.Exit(1)
}
ret := make(map[string]interface{})
err = json.Unmarshal(b.Bytes(), &ret)
if err != nil {
r.Reporter.Errorf("Failed to generate output for ingress '%s': %v", ingress.ID(), err)
os.Exit(1)
}
err = output.Print(ret)
if err != nil {
r.Reporter.Errorf("Failed to output ingress '%s': %v", ingress.ID(), err)
os.Exit(1)
}
return
}
entries := generateEntriesOutput(cluster, ingress)
ingressOutput := ""
keys := helper.MapKeys(entries)
sort.Strings(keys)
minWidth := getMinWidth(keys)
for _, key := range keys {
ingressOutput += fmt.Sprintf("%s: %s\n", key, strings.Repeat(" ", minWidth-len(key))+entries[key])
}
fmt.Print(ingressOutput)
}

func getMinWidth(keys []string) int {
minWidth := 0
for _, key := range keys {
if len(key) > minWidth {
minWidth = len(key)
}
}
return minWidth
}

func generateEntriesOutput(cluster *cmv1.Cluster, ingress *cmv1.Ingress) map[string]string {
private := false
if ingress.Listening() == cmv1.ListeningMethodInternal {
private = true
}
entries := map[string]string{
"ID": ingress.ID(),
"Cluster ID": cluster.ID(),
"Default": strconv.FormatBool(ingress.Default()),
"Private": strconv.FormatBool(private),
"LB-Type": string(ingress.LoadBalancerType()),
}
// These are only available for ingress v2
wildcardPolicy := string(ingress.RouteWildcardPolicy())
if wildcardPolicy != "" {
entries["Wildcard Policy"] = string(ingress.RouteWildcardPolicy())
}
namespaceOwnershipPolicy := string(ingress.RouteNamespaceOwnershipPolicy())
if namespaceOwnershipPolicy != "" {
entries["Namespace Ownership Policy"] = namespaceOwnershipPolicy
}
routeSelectors := ""
if len(ingress.RouteSelectors()) > 0 {
routeSelectors = fmt.Sprintf("%v", ingress.RouteSelectors())
}
if routeSelectors != "" {
entries["Route Selectors"] = routeSelectors
}
excludedNamespaces := helper.SliceToSortedString(ingress.ExcludedNamespaces())
if excludedNamespaces != "" {
entries["Excluded Namespaces"] = excludedNamespaces
}
componentRoutes := ""
for component, value := range ingress.ComponentRoutes() {
keys := helper.MapKeys(entries)
minWidth := getMinWidth(keys)
depth := 4
componentRouteEntries := map[string]string{
"Hostname": value.Hostname(),
"TLS Secret Ref": value.TlsSecretRef(),
}
componentRoutes += fmt.Sprintf("%s: \n", strings.Repeat(" ", depth)+component)
depth *= 2
for key, entry := range componentRouteEntries {
componentRoutes += fmt.Sprintf(
"%s: %s\n",
strings.Repeat(" ", depth)+key,
strings.Repeat(" ", minWidth-len(key)-depth)+entry,
)
}
}
if componentRoutes != "" {
componentRoutes = fmt.Sprintf("\n%s", componentRoutes)
//remove extra \n at the end
componentRoutes = componentRoutes[:len(componentRoutes)-1]
entries["Component Routes"] = componentRoutes
}
return entries
}
33 changes: 7 additions & 26 deletions cmd/edit/ingress/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,11 @@ func run(cmd *cobra.Command, argv []string) {
r := rosa.NewRuntime().WithAWS().WithOCM()
defer r.Cleanup()

ingressID := argv[0]
if !ingressKeyRE.MatchString(ingressID) {
ingressKey := argv[0]
if !ingressKeyRE.MatchString(ingressKey) {
r.Reporter.Errorf(
"Ingress identifier '%s' isn't valid: it must contain only letters or digits",
ingressID,
ingressKey,
)
os.Exit(1)
}
Expand Down Expand Up @@ -223,7 +223,7 @@ func run(cmd *cobra.Command, argv []string) {
private = &privArg
}
// Edit API endpoint instead of ingresses
if ingressID == "api" {
if ingressKey == "api" {
clusterConfig := ocm.Spec{
Private: private,
}
Expand All @@ -233,32 +233,13 @@ func run(cmd *cobra.Command, argv []string) {
r.Reporter.Errorf("Failed to update cluster API on cluster '%s': %v", clusterKey, err)
os.Exit(1)
}
r.Reporter.Infof("Updated ingress '%s' on cluster '%s'", ingressID, clusterKey)
r.Reporter.Infof("Updated ingress '%s' on cluster '%s'", ingressKey, clusterKey)
os.Exit(0)
}

// Try to find the ingress:
r.Reporter.Debugf("Loading ingresses for cluster '%s'", clusterKey)
ingresses, err := r.OCMClient.GetIngresses(cluster.ID())
ingress, err := r.OCMClient.GetIngress(cluster.ID(), ingressKey)
if err != nil {
r.Reporter.Errorf("Failed to get ingresses for cluster '%s': %v", clusterKey, err)
os.Exit(1)
}

var ingress *cmv1.Ingress
for _, item := range ingresses {
if ingressID == "apps" && item.Default() {
ingress = item
}
if ingressID == "apps2" && !item.Default() {
ingress = item
}
if item.ID() == ingressID {
ingress = item
}
}
if ingress == nil {
r.Reporter.Errorf("Failed to get ingress '%s' for cluster '%s'", ingressID, clusterKey)
r.Reporter.Errorf("Failed to fetch ingress: %v", err)
os.Exit(1)
}

Expand Down
26 changes: 26 additions & 0 deletions pkg/ocm/ingresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,35 @@ limitations under the License.
package ocm

import (
"fmt"

cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
)

func (c *Client) GetIngress(clusterId string, ingressKey string) (*cmv1.Ingress, error) {
ingresses, err := c.GetIngresses(clusterId)
if err != nil {
return nil, err
}

var ingress *cmv1.Ingress
for _, item := range ingresses {
if ingressKey == "apps" && item.Default() {
ingress = item
}
if ingressKey == "apps2" && !item.Default() {
ingress = item
}
if item.ID() == ingressKey {
ingress = item
}
}
if ingress == nil {
return nil, fmt.Errorf("Failed to get ingress '%s' for cluster '%s'", ingressKey, clusterId)
}
return ingress, nil
}

func (c *Client) GetIngresses(clusterID string) ([]*cmv1.Ingress, error) {
response, err := c.ocm.ClustersMgmt().V1().
Clusters().Cluster(clusterID).
Expand Down

0 comments on commit 1041130

Please sign in to comment.