Skip to content
This repository has been archived by the owner on Aug 27, 2019. It is now read-only.

Commit

Permalink
Added new account subcommand 'orgs', lists organizations: SREP-1736
Browse files Browse the repository at this point in the history
  • Loading branch information
alima committed Jul 19, 2019
1 parent 6a3ca17 commit b1426a7
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 0 deletions.
3 changes: 3 additions & 0 deletions cmd/uhc/account/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ import (

"github.com/spf13/cobra"

"github.com/openshift-online/uhc-cli/cmd/uhc/account/orgs"
"github.com/openshift-online/uhc-cli/cmd/uhc/account/quota"
"github.com/openshift-online/uhc-cli/cmd/uhc/account/roles"
"github.com/openshift-online/uhc-cli/cmd/uhc/account/status"
"github.com/openshift-online/uhc-cli/cmd/uhc/account/users"
)

// Cmd ...
var Cmd = &cobra.Command{
Use: "account COMMAND",
Short: "Get information about users.",
Expand All @@ -37,6 +39,7 @@ var Cmd = &cobra.Command{

func init() {
Cmd.AddCommand(quota.Cmd)
Cmd.AddCommand(orgs.Cmd)
Cmd.AddCommand(status.Cmd)
Cmd.AddCommand(roles.Cmd)
Cmd.AddCommand(users.Cmd)
Expand Down
179 changes: 179 additions & 0 deletions cmd/uhc/account/orgs/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
Copyright (c) 2019 Red Hat, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package orgs

import (
"bytes"
"encoding/json"
"fmt"
"os"
"strings"

"github.com/spf13/cobra"

"github.com/openshift-online/uhc-cli/pkg/config"
flags "github.com/openshift-online/uhc-cli/pkg/flags"
table "github.com/openshift-online/uhc-cli/pkg/table"
amv1 "github.com/openshift-online/uhc-sdk-go/pkg/client/accountsmgmt/v1"
)

var args struct {
columns string
parameter []string
padding int
}

// Cmd ...
var Cmd = &cobra.Command{
Use: "orgs",
Short: "List organizations.",
Long: "Display a list of organizations.",
Run: run,
}

func init() {
// Add flags to rootCmd:
fs := Cmd.Flags()
flags.AddParameterFlag(fs, &args.parameter)
fs.StringVar(
&args.columns,
"columns",
"id,href,name", // Default value gets assigned later as connection is needed.
"Organization identifier. Defaults to the organization of the current user.",
)
fs.IntVar(
&args.padding,
"padding",
45,
"Takes padding for custom columns, default to 45.",
)
}

func run(cmd *cobra.Command, argv []string) {

// Load the configuration file:
cfg, err := config.Load()
if err != nil {
fmt.Fprintf(os.Stderr, "Can't load config file: %v\n", err)
os.Exit(1)
}
if cfg == nil {
fmt.Fprintf(os.Stderr, "Not logged in, run the 'login' command\n")
os.Exit(1)
}

// Check that the configuration has credentials or tokens that haven't have expired:
armed, err := cfg.Armed()
if err != nil {
fmt.Fprintf(os.Stderr, "Can't check if tokens have expired: %v\n", err)
os.Exit(1)
}
if !armed {
fmt.Fprintf(os.Stderr, "Tokens have expired, run the 'login' command\n")
os.Exit(1)
}

// Create the connection, and remember to close it:
connection, err := cfg.Connection()
if err != nil {
fmt.Fprintf(os.Stderr, "Can't create connection: %v\n", err)
os.Exit(1)
}
defer connection.Close()

// Indices
pageIndex := 1
pageSize := 100

// Setting column names and padding size
// Update our column name displaying variable:
args.columns = strings.Replace(args.columns, " ", "", -1)
colUpper := strings.ToUpper(args.columns)
colUpper = strings.Replace(colUpper, ".", " ", -1)
columnNames := strings.Split(colUpper, ",")
paddingByColumn := []int{29, 65, 70}
if args.columns != "id,href,name" {
paddingByColumn = []int{args.padding}
}

// Print Header Row:
table.PrintPadded(os.Stdout, columnNames, paddingByColumn)
fmt.Println()

for {
// Next page request:
request := connection.AccountsMgmt().V1().Organizations().
List().
Page(pageIndex).
Size(pageSize)

// Apply parameters
flags.ApplyParameterFlag(request, args.parameter)

// Fetch next page
orgList, err := request.Send()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to retrieve organization list: %v\n", err)
os.Exit(1)
}

// Display organization information
orgList.Items().Each(func(org *amv1.Organization) bool {
// String to output marshal -
// Map used to parse Organization data -
// Writer to body variable:
var body string
var jsonBody map[string]interface{}
boddyBuffer := bytes.NewBufferString(body)

// Write Organization data to body variable:
err := amv1.MarshalOrganization(org, boddyBuffer)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to marshal organization into byte buffer: %s\n", err)
os.Exit(1)
}

// Get JSON from Organization bytes
err = json.Unmarshal(boddyBuffer.Bytes(), &jsonBody)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to turn organization bytes into JSON map: %s\n", err)
os.Exit(1)
}

// Loop through wanted columns and populate an organization instance
iter := strings.Split(args.columns, ",")
thisOrg := []string{}
for _, element := range iter {
value, status := table.FindMapValue(jsonBody, element)
if !status {
value = "NONE"
}
thisOrg = append(thisOrg, value)
}
table.PrintPadded(os.Stdout, thisOrg, paddingByColumn)
return true
})

// Break if we reach last page
if orgList.Size() < pageSize {
break
}

pageIndex++
}
fmt.Println()
}
88 changes: 88 additions & 0 deletions pkg/table/table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
Copyright (c) 2019 Red Hat, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// This file contains functions that help displaying information in a tabular form

package table

import (
"fmt"
"io"
"strings"
)

// FindMapValue will find a key and retrieve its value from the given map. The key has to be
// a string and can be multilayered, for example `foo.bar`. Returns the value and a boolean
// indicating if the value was found.
func FindMapValue(data map[string]interface{}, key string) (string, bool) {

// Split key into array
keys := strings.Split(key, ".")

// loop though elements in sliced string:
for _, element := range keys {

// if key is found, continue:
if val, ok := data[element]; ok {

switch typed := val.(type) {

// If key points to interface insance:
case map[string]interface{}:
data = typed

// If key points to an end value:
default:
return fmt.Sprintf("%v", typed), true

}

} else { // Key not in map
return "", false
}
}

return "", false
}

// PrintPadded turns an array into a padded string and outputs it into the given writer.
func PrintPadded(w io.Writer, columns []string, padding []int) {
updated := updateRowPad(columns, padding)
var finalString string
for _, str := range updated {
finalString = fmt.Sprint(finalString, str)
}
fmt.Fprint(w, finalString+"\n")
}

func updateRowPad(columnList []string, columnPad []int) []string {
st := columnList
fixLen := len(columnPad) - len(st)
if fixLen < 0 {
valueToUse := columnPad[len(columnPad)-1]
for i := 0; i < fixLen*(-1); i++ {
columnPad = append(columnPad, valueToUse)
}
}
for i := range st {
if len(st[i]) < columnPad[i] {
st[i] = st[i] + strings.Repeat(" ", columnPad[i]-len(st[i]))
} else {
st[i] = st[i][:columnPad[i]-2] + " "
}
}
return st
}

0 comments on commit b1426a7

Please sign in to comment.