Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update environment.go #273

Merged
merged 6 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 115 additions & 43 deletions cmd/describe/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package describe
import (
"encoding/json"
"fmt"
"strings"

"github.com/dream11/odin/internal/service"
"github.com/dream11/odin/pkg/constant"
"github.com/dream11/odin/pkg/table"
v1 "github.com/dream11/odin/proto/gen/go/dream11/od/dto/v1"
environment "github.com/dream11/odin/proto/gen/go/dream11/od/environment/v1"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)

var name string
Expand Down Expand Up @@ -64,66 +66,136 @@ func writeOutput(response *environment.DescribeEnvironmentResponse, format strin

switch format {
case constant.TEXT:
writeAsTextEnvResponse(response)
printEnvInfo(response)
case constant.JSON:
writeAsJSONEnvResponse(response)
default:
log.Fatal("Unknown output format: ", format)
}
}

func writeAsTextEnvResponse(response *environment.DescribeEnvironmentResponse) {

tableHeaders := []string{"Name",
"state",
"autoDeletionTime",
"cloudProviderAccounts",
"createdBy",
"updatedBy",
"createdAt",
"updatedAt",
"services"}
var tableData [][]interface{}
func printEnvInfo(response *environment.DescribeEnvironmentResponse) {
env := response.Environment
var accountInfoList []string

// Extracting necessary fields
name := env.GetName()
envType := env.GetProvisioningType()
state := env.GetStatus()
autoDeletionTime := env.AutoDeletionTime.AsTime().String()
cloudProviderAccounts := []string{}
providerAccountCluster := map[string][]string{}
for _, accountInfo := range env.AccountInformation {
accountInfoList = append(accountInfoList, accountInfo.ProviderAccountName)
}
accountInfoListJSON, err := json.Marshal(accountInfoList)
if err != nil {
log.Fatal("Failed to marshal account info list: ", err)
cloudProviderAccounts = append(cloudProviderAccounts, accountInfo.ProviderAccountName)
providerAccountCluster[accountInfo.ProviderAccountName] = getClusterNames(accountInfo)
}

var servicesSummary []map[string]interface{}
createdBy := env.GetCreatedBy()
updatedBy := env.GetUpdatedBy()
createdAt := env.CreatedAt.AsTime().String()
updatedAt := env.UpdatedAt.AsTime().String()
services := []string{}
for _, svc := range env.Services {
serviceMap := map[string]interface{}{
"name": svc.Name,
"version": svc.Version,
"status": svc.Status,
if serviceName == "" {
services = append(services, fmt.Sprintf(" - name: %s\n version: %s", *svc.Name, *svc.Version))
} else {
if serviceName == *svc.Name {
var customServicesOp = []string{}
customServicesOp = append(customServicesOp, fmt.Sprintf(" - name: %s\n version: %s\n", *svc.Name, *svc.Version))
customServicesOp = append(customServicesOp, " components: \n")
componentBytes, err := json.MarshalIndent(svc.Components, "", " ")
if err != nil {
log.Fatal("Failed to marshal services summary: ", err)
}
var formatedComponentData = string(componentBytes)
formatedComponentData, _ = ConvertJSONToYAML(formatedComponentData)
lines := strings.Split(formatedComponentData, "\n")

for i, line := range lines {
lines[i] = "\t" + line
}
formatedComponentData = strings.Join(lines, "\n")
// Add two tabs before each line in the string
customServicesOp = append(customServicesOp, formatedComponentData)

services = append(services, strings.Join(customServicesOp, ""))
}

}
if len(svc.Components) > 0 {
serviceMap["components"] = svc.Components
}

// Formatting and printing the information
fmt.Printf("Describing Env: %s\n\n", name)
fmt.Printf("name: %s\n", name)
fmt.Printf("envType: %s\n", envType)
fmt.Printf("state: %s\n", state)
fmt.Printf("autoDeletionTime: \"%s\"\n", autoDeletionTime)
fmt.Printf("cloudProviderAccounts:\n")
for _, account := range cloudProviderAccounts {
fmt.Printf(" - %s\n", account)
}
fmt.Printf("cluster:\n")
for account, clusters := range providerAccountCluster {
fmt.Printf(" - %s\n", account)
for _, cluster := range clusters {
fmt.Printf(" - %s\n", cluster)
}
servicesSummary = append(servicesSummary, serviceMap)

}
servicesSummaryJSON, err := json.Marshal(servicesSummary)
fmt.Printf("createdBy: %s\n", createdBy)
fmt.Printf("updatedBy: %s\n", updatedBy)
fmt.Printf("createdAt: \"%s\"\n", createdAt)
fmt.Printf("updatedAt: \"%s\"\n", updatedAt)
fmt.Printf("services:\n%s\n", strings.Join(services, "\n"))
}

// ConvertJSONToYAML takes a JSON string as input and returns a formatted YAML string
func ConvertJSONToYAML(jsonStr string) (string, error) {
// Unmarshal the JSON into a generic structure
var jsonData interface{}
err := json.Unmarshal([]byte(jsonStr), &jsonData)
if err != nil {
log.Fatal("Failed to marshal services summary: ", err)
return "", fmt.Errorf("failed to parse JSON: %v", err)
}

tableData = append(tableData, []interface{}{
env.GetName(),
env.GetStatus(),
env.AutoDeletionTime.AsTime().String(),
string(accountInfoListJSON),
env.GetCreatedBy(),
env.GetUpdatedBy(),
env.CreatedAt.AsTime().String(),
env.UpdatedAt.AsTime().String(),
string(servicesSummaryJSON),
})
// Marshal the structure into YAML
yamlData, err := yaml.Marshal(jsonData)
if err != nil {
return "", fmt.Errorf("failed to convert to YAML: %v", err)
}

// Return the YAML string
return string(yamlData), nil
}

table.Write(tableHeaders, tableData)
func findValueByKey(val interface{}, key string) string {
switch v := val.(type) {
case map[string]interface{}: // If it's a map, check for the key
if value, ok := v[key]; ok {
return fmt.Sprintf("%v", value)
}
// Recurse through nested maps or slices
for _, subVal := range v {
return findValueByKey(subVal, key)
}
case []interface{}: // If it's a slice, recurse for each element
for _, item := range v {
return findValueByKey(item, key)
}
}
return "" // Key not found
}

func getClusterNames(information *v1.AccountInformation) []string {
clusterNames := []string{}
for _, service := range information.ServiceAccountsSnapshot.Account.Services {
if service.Category == "KUBERNETES" {
for key, val := range service.GetData().AsMap() {
if key == "clusters" {
clusterNames = append(clusterNames, findValueByKey(val, "name"))
}
}
}
}
return clusterNames
}

func writeAsJSONEnvResponse(response *environment.DescribeEnvironmentResponse) {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/google/uuid v1.6.0
github.com/mitchellh/cli v1.1.5
github.com/olekukonko/tablewriter v0.0.5
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.1
)

Expand Down
17 changes: 17 additions & 0 deletions internal/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
// Service performs operation on service like deploy. undeploy
type Service struct{}

var responseMap = make(map[string]string)

// DeployService deploys service
func (e *Service) DeployService(ctx *context.Context, request *serviceProto.DeployServiceRequest) error {
conn, requestCtx, err := grpcClient(ctx)
Expand Down Expand Up @@ -50,6 +52,7 @@ func (e *Service) DeployService(ctx *context.Context, request *serviceProto.Depl

if response != nil {
message = util.GenerateResponseMessage(response.GetServiceResponse())
printFailedComponentMsgOnce(response.GetServiceResponse())
spinnerInstance.Prefix = fmt.Sprintf(" %s ", message)
spinnerInstance.Start()
}
Expand All @@ -59,6 +62,19 @@ func (e *Service) DeployService(ctx *context.Context, request *serviceProto.Depl
return err
}

func printFailedComponentMsgOnce(response *serviceProto.ServiceResponse) {
for _, compMessage := range response.ComponentsStatus {
componentActionKey := compMessage.GetComponentName() + compMessage.GetComponentAction() + compMessage.GetComponentStatus()
//code to not print the same message for component action again
if responseMap[componentActionKey] == "" {
if compMessage.GetComponentStatus() == "FAILED" {
log.Error(fmt.Sprintf("Component %s %s %s %s", compMessage.GetComponentName(), compMessage.GetComponentAction(), compMessage.GetComponentStatus(), compMessage.GetError()))
}
responseMap[componentActionKey] = componentActionKey
}
}
}

// DeployServiceSet deploys service-set
func (e *Service) DeployServiceSet(ctx *context.Context, request *serviceProto.DeployServiceSetRequest) error {
conn, requestCtx, err := grpcClient(ctx)
Expand Down Expand Up @@ -93,6 +109,7 @@ func (e *Service) DeployServiceSet(ctx *context.Context, request *serviceProto.D
if response != nil {
message = ""
for _, serviceResponse := range response.GetServices() {
printFailedComponentMsgOnce(serviceResponse.GetServiceResponse())
message += util.GenerateResponseMessage(serviceResponse.GetServiceResponse())
}
spinnerInstance.Prefix = fmt.Sprintf(" %s ", message)
Expand Down
2 changes: 1 addition & 1 deletion pkg/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func IsIPAddress(address string) bool {
func GenerateResponseMessage(response *v1.ServiceResponse) string {
message := fmt.Sprintf("\n Service %s %s", response.ServiceStatus.ServiceAction, response.ServiceStatus)
for _, compMessage := range response.ComponentsStatus {
message += fmt.Sprintf("\n Component %s %s %s %s", compMessage.ComponentName, compMessage.ComponentAction, compMessage.ComponentStatus, compMessage.Error)
message += fmt.Sprintf("\n Component %s %s %s ", compMessage.ComponentName, compMessage.ComponentAction, compMessage.ComponentStatus)
}
return message
}
Expand Down
Loading