-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OCM-6528 | feat: add describe ingress cmd
- Loading branch information
Showing
7 changed files
with
339 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
package ingress | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"os" | ||
|
||
c "github.com/openshift-online/ocm-cli/pkg/cluster" | ||
"github.com/openshift-online/ocm-cli/pkg/dump" | ||
i "github.com/openshift-online/ocm-cli/pkg/ingress" | ||
"github.com/openshift-online/ocm-cli/pkg/ocm" | ||
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var args struct { | ||
json bool | ||
output bool | ||
ingressKey string | ||
} | ||
|
||
var Cmd = &cobra.Command{ | ||
Use: "ingress [flags] {CLUSTER_NAME|CLUSTER_ID|CLUSTER_EXTERNAL_ID} -i ingress_key", | ||
Short: "Show details of an ingress", | ||
Long: "Show details of an ingress identified by name, or identifier", | ||
RunE: run, | ||
} | ||
|
||
func init() { | ||
// Add flags to rootCmd: | ||
flags := Cmd.Flags() | ||
flags.BoolVar( | ||
&args.output, | ||
"output", | ||
false, | ||
"Output result into JSON file.", | ||
) | ||
flags.BoolVar( | ||
&args.json, | ||
"json", | ||
false, | ||
"Output the entire JSON structure", | ||
) | ||
flags.StringVarP( | ||
&args.ingressKey, | ||
"ingress", | ||
"i", | ||
"", | ||
"Ingress identifier", | ||
) | ||
} | ||
|
||
func run(cmd *cobra.Command, argv []string) error { | ||
// Check that there is exactly one cluster name, identifir or external identifier in the | ||
// command line arguments: | ||
if len(argv) != 1 { | ||
fmt.Fprintf( | ||
os.Stderr, | ||
"Expected exactly one cluster name, identifier or external identifier "+ | ||
"is required\n", | ||
) | ||
os.Exit(1) | ||
} | ||
|
||
// Check that the cluster key (name, identifier or external identifier) given by the user | ||
// is reasonably safe so that there is no risk of SQL injection: | ||
key := argv[0] | ||
if !c.IsValidClusterKey(key) { | ||
fmt.Fprintf( | ||
os.Stderr, | ||
"Cluster name, identifier or external identifier '%s' isn't valid: it "+ | ||
"must contain only letters, digits, dashes and underscores\n", | ||
key, | ||
) | ||
os.Exit(1) | ||
} | ||
ingressKey := args.ingressKey | ||
if ingressKey == "" { | ||
fmt.Fprintf( | ||
os.Stderr, | ||
"Ingress identifier must be supplied\n", | ||
) | ||
os.Exit(1) | ||
} | ||
|
||
// Create the client for the OCM API: | ||
connection, err := ocm.NewConnection().Build() | ||
if err != nil { | ||
return fmt.Errorf("Failed to create OCM connection: %v", err) | ||
} | ||
defer connection.Close() | ||
|
||
cluster, err := c.GetCluster(connection, key) | ||
if err != nil { | ||
return fmt.Errorf("Can't retrieve cluster for key '%s': %v", key, err) | ||
} | ||
|
||
clusterId := cluster.ID() | ||
response, err := connection.ClustersMgmt().V1(). | ||
Clusters().Cluster(clusterId). | ||
Ingresses(). | ||
List().Page(1).Size(-1). | ||
Send() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
ingresses := response.Items().Slice() | ||
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 fmt.Errorf("Failed to get ingress '%s' for cluster '%s'", ingressKey, clusterId) | ||
} | ||
|
||
if args.output { | ||
// Create a filename based on cluster name: | ||
filename := fmt.Sprintf("ingress-%s-%s.json", cluster.ID(), ingress.ID()) | ||
|
||
// Attempt to create file: | ||
myFile, err := os.Create(filename) | ||
if err != nil { | ||
return fmt.Errorf("Failed to create file: %v", err) | ||
} | ||
|
||
// Dump encoder content into file: | ||
err = cmv1.MarshalIngress(ingress, myFile) | ||
if err != nil { | ||
return fmt.Errorf("Failed to Marshal ingress into file: %v", err) | ||
} | ||
} | ||
|
||
// Get full API response (JSON): | ||
if args.json { | ||
// Buffer for pretty output: | ||
buf := new(bytes.Buffer) | ||
fmt.Println() | ||
|
||
// Convert cluster to JSON and dump to encoder: | ||
err = cmv1.MarshalIngress(ingress, buf) | ||
if err != nil { | ||
return fmt.Errorf("Failed to Marshal ingress into JSON encoder: %v", err) | ||
} | ||
|
||
err = dump.Pretty(os.Stdout, buf.Bytes()) | ||
if err != nil { | ||
return fmt.Errorf("Can't print body: %v", err) | ||
} | ||
|
||
} else { | ||
err = i.PrintIngressDescription(ingress, cluster) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package ingress | ||
|
||
import ( | ||
"fmt" | ||
"sort" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/openshift-online/ocm-cli/pkg/utils" | ||
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" | ||
) | ||
|
||
func PrintIngressDescription(ingress *cmv1.Ingress, cluster *cmv1.Cluster) error { | ||
entries := generateEntriesOutput(cluster, ingress) | ||
ingressOutput := "" | ||
keys := utils.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) | ||
return nil | ||
} | ||
|
||
// Min width is defined as the length of the longest string | ||
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 := utils.SliceToSortedString(ingress.ExcludedNamespaces()) | ||
if excludedNamespaces != "" { | ||
entries["Excluded Namespaces"] = excludedNamespaces | ||
} | ||
componentRoutes := "" | ||
componentKeys := utils.MapKeys(ingress.ComponentRoutes()) | ||
sort.Strings(componentKeys) | ||
for _, component := range componentKeys { | ||
value := ingress.ComponentRoutes()[component] | ||
keys := utils.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 | ||
paramKeys := utils.MapKeys(componentRouteEntries) | ||
sort.Strings(paramKeys) | ||
for _, param := range paramKeys { | ||
componentRoutes += fmt.Sprintf( | ||
"%s: %s\n", | ||
strings.Repeat(" ", depth)+param, | ||
strings.Repeat(" ", minWidth-len(param)-depth)+componentRouteEntries[param], | ||
) | ||
} | ||
} | ||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package ingress | ||
|
||
import ( | ||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" | ||
v1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" | ||
) | ||
|
||
var _ = Describe("Get min width for output", func() { | ||
It("retrieves the min width", func() { | ||
minWidth := getMinWidth([]string{"a", "ab", "abc", "def"}) | ||
Expect(minWidth).To(Equal(3)) | ||
}) | ||
When("empty slice", func() { | ||
It("retrieves the min width as 0", func() { | ||
minWidth := getMinWidth([]string{}) | ||
Expect(minWidth).To(Equal(0)) | ||
}) | ||
}) | ||
}) | ||
|
||
var _ = Describe("Retrieve map of entries for output", func() { | ||
It("retrieves map", func() { | ||
cluster, err := cmv1.NewCluster().ID("123").Build() | ||
Expect(err).To(BeNil()) | ||
ingress, err := cmv1.NewIngress(). | ||
ID("123"). | ||
Default(true). | ||
Listening(cmv1.ListeningMethodExternal). | ||
LoadBalancerType(cmv1.LoadBalancerFlavorNlb). | ||
RouteWildcardPolicy(cmv1.WildcardPolicyWildcardsAllowed). | ||
RouteNamespaceOwnershipPolicy(cmv1.NamespaceOwnershipPolicyStrict). | ||
RouteSelectors(map[string]string{ | ||
"test-route": "test-selector", | ||
}). | ||
ExcludedNamespaces("test", "test2"). | ||
ComponentRoutes(map[string]*cmv1.ComponentRouteBuilder{ | ||
string(cmv1.ComponentRouteTypeOauth): v1.NewComponentRoute(). | ||
Hostname("oauth-hostname").TlsSecretRef("oauth-secret"), | ||
}). | ||
Build() | ||
Expect(err).To(BeNil()) | ||
mapOutput := generateEntriesOutput(cluster, ingress) | ||
Expect(mapOutput).To(HaveLen(10)) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package ingress | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
func TestEditCluster(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "Describe ingress suite") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters