github.com/verrazzano/verrazzano@v1.7.0/tools/vz/cmd/install/state.go (about) 1 // Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package install 5 6 import ( 7 "fmt" 8 "os" 9 "sort" 10 "strings" 11 "time" 12 13 "github.com/spf13/cobra" 14 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1" 15 "github.com/verrazzano/verrazzano/tools/vz/pkg/constants" 16 "github.com/verrazzano/verrazzano/tools/vz/pkg/helpers" 17 "sigs.k8s.io/controller-runtime/pkg/client" 18 ) 19 20 // displayInstallationProgress Checks state of components until all of them are Ready or specified timeout is reached 21 func displayInstallationProgress(cmd *cobra.Command, vzHelper helpers.VZHelper, duration time.Duration) error { 22 client, err := vzHelper.GetClient(cmd) 23 if err != nil { 24 fmt.Println("Error in client", err) 25 return err 26 } 27 time.Sleep(time.Second * 10) 28 fmt.Print("\033[2J\033[H") // Clear the console before entering the loop 29 startTime := time.Now() 30 for { 31 // Save the cursor position 32 fmt.Print("\033[s") 33 statusMap, err := getEnabledComponentMap(client) 34 if err != nil { 35 fmt.Println("Error in fetching verrazzano resource", err) 36 return err 37 } 38 if len(statusMap) == 0 { 39 return fmt.Errorf("No enabled components found") 40 } 41 displayComponentStatus(statusMap) 42 progress, nonReady := calculateProgress(statusMap) 43 displayProgressBar(progress) 44 if isAllReady(statusMap) { 45 fmt.Println("\nInstallation Completed. All components are ready") 46 break 47 } else { 48 if time.Since(startTime) >= duration { 49 50 return fmt.Errorf("timed out waiting for components to be ready-> %s", strings.TrimPrefix(strings.Join(nonReady, ", "), ", ")) 51 } 52 time.Sleep(constants.RefreshRate) 53 // Restore the cursor position to the beginning of the table and the progress bar 54 fmt.Print("\033[u") 55 } 56 } 57 return nil 58 } 59 60 // displayComponentStatus displays the component status in the console. 61 // Parameter:- statusMap: A map containing the component names and their status 62 func displayComponentStatus(statusMap map[string]v1alpha1.CompStateType) { 63 // Move the cursor to the top-left position and clear the console 64 fmt.Fprintf(os.Stdout, "\033[H\033[J") 65 fmt.Println("Component\t\t\t\t\tStatus") 66 fmt.Println("-------------------------------------------------------") 67 // Create a slice to hold the component names for sorting 68 var componentNames []string 69 for componentName := range statusMap { 70 componentNames = append(componentNames, componentName) 71 } 72 sort.Strings(componentNames) 73 // Display the components in alphabetical order 74 for _, componentName := range componentNames { 75 status := statusMap[componentName] 76 // Move the cursor to the beginning of the current line and clear the line 77 fmt.Fprintf(os.Stdout, "\r\033[K") 78 fmt.Printf("%-40s\t%s\n", componentName, status) 79 } 80 } 81 82 // isAllReady checks if all components are in "Ready" state. 83 // Returns: bool: True if all components are in "Ready" state, false otherwise 84 func isAllReady(statusMap map[string]v1alpha1.CompStateType) bool { 85 for _, status := range statusMap { 86 if status != "Ready" { 87 return false 88 } 89 } 90 return true 91 } 92 93 // getEnabledComponentMap retrieves the enabled components and their status. 94 func getEnabledComponentMap(client client.Client) (map[string]v1alpha1.CompStateType, error) { 95 vz, err := helpers.FindVerrazzanoResource(client) 96 if err != nil { 97 return nil, err 98 } 99 statusMap := make(map[string]v1alpha1.CompStateType) 100 for componentName, componentStatus := range vz.Status.Components { 101 if componentStatus.State != "Disabled" { 102 statusMap[componentName] = v1alpha1.CompStateType(componentStatus.State) 103 } 104 } 105 return statusMap, nil 106 } 107 108 // calculateProgress calculates the installation progress based on the number of components in "Ready" state. 109 func calculateProgress(statusMap map[string]v1alpha1.CompStateType) (float64, []string) { 110 sync := make([]string, 1) 111 readyCount := 0 112 totalCount := len(statusMap) 113 for index, status := range statusMap { 114 if status == "Ready" { 115 readyCount++ 116 } else { 117 sync = append(sync, index) 118 } 119 } 120 return float64(readyCount) / float64(totalCount), sync 121 } 122 123 // displayProgressBar displays the progress bar based on the installation progress. 124 // Parameter:- progress: The installation progress percentage 125 func displayProgressBar(progress float64) { 126 fmt.Print("[") 127 slides := int(progress * float64(constants.TotalWidth)) 128 for i := 0; i < constants.TotalWidth; i++ { 129 if i < slides { 130 // Set color to green 131 fmt.Print("\033[32m#") 132 } else { 133 fmt.Print(" ") 134 } 135 } 136 // Reset color back to the default 137 fmt.Print("\033[0m") 138 fmt.Printf("] %.0f%%\r", progress*100) 139 }