volcano.sh/volcano@v1.9.0/pkg/cli/util/util.go (about) 1 /* 2 Copyright 2019 The Volcano Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package util 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 "path/filepath" 24 "strings" 25 "time" 26 27 "github.com/spf13/cobra" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 30 v1 "k8s.io/api/core/v1" 31 "k8s.io/apimachinery/pkg/api/resource" 32 "k8s.io/client-go/rest" 33 "k8s.io/client-go/tools/clientcmd" 34 35 vcbus "volcano.sh/apis/pkg/apis/bus/v1alpha1" 36 "volcano.sh/apis/pkg/apis/helpers" 37 "volcano.sh/apis/pkg/client/clientset/versioned" 38 ) 39 40 // CommonFlags are the flags that most command lines have. 41 type CommonFlags struct { 42 Master string 43 Kubeconfig string 44 } 45 46 // InitFlags initializes the common flags for most command lines. 47 func InitFlags(cmd *cobra.Command, cf *CommonFlags) { 48 cmd.Flags().StringVarP(&cf.Master, "master", "s", "", "the address of apiserver") 49 50 kubeConfFile := os.Getenv("KUBECONFIG") 51 if kubeConfFile == "" { 52 if home := HomeDir(); home != "" { 53 kubeConfFile = filepath.Join(home, ".kube", "config") 54 } 55 } 56 cmd.Flags().StringVarP(&cf.Kubeconfig, "kubeconfig", "k", kubeConfFile, "(optional) absolute path to the kubeconfig file") 57 } 58 59 // HomeDir gets the env $HOME. 60 func HomeDir() string { 61 if h := os.Getenv("HOME"); h != "" { 62 return h 63 } 64 return os.Getenv("USERPROFILE") // windows 65 } 66 67 // BuildConfig builds the configure file for command lines. 68 func BuildConfig(master, kubeconfig string) (*rest.Config, error) { 69 return clientcmd.BuildConfigFromFlags(master, kubeconfig) 70 } 71 72 // PopulateResourceListV1 takes strings of form <resourceName1>=<value1>,<resourceName2>=<value2> and returns ResourceList. 73 func PopulateResourceListV1(spec string) (v1.ResourceList, error) { 74 // empty input gets a nil response to preserve generator test expected behaviors 75 if spec == "" { 76 return nil, nil 77 } 78 79 result := v1.ResourceList{} 80 resourceStatements := strings.Split(spec, ",") 81 for _, resourceStatement := range resourceStatements { 82 parts := strings.Split(resourceStatement, "=") 83 if len(parts) != 2 { 84 return nil, fmt.Errorf("invalid argument syntax %v, expected <resource>=<value>", resourceStatement) 85 } 86 resourceName := v1.ResourceName(parts[0]) 87 resourceQuantity, err := resource.ParseQuantity(parts[1]) 88 if err != nil { 89 return nil, err 90 } 91 result[resourceName] = resourceQuantity 92 } 93 return result, nil 94 } 95 96 // CreateQueueCommand executes a command such as open/close 97 func CreateQueueCommand(vcClient *versioned.Clientset, ns, name string, action vcbus.Action) error { 98 queue, err := vcClient.SchedulingV1beta1().Queues().Get(context.TODO(), name, metav1.GetOptions{}) 99 if err != nil { 100 return err 101 } 102 ctrlRef := metav1.NewControllerRef(queue, helpers.V1beta1QueueKind) 103 cmd := &vcbus.Command{ 104 ObjectMeta: metav1.ObjectMeta{ 105 GenerateName: fmt.Sprintf("%s-%s-", 106 queue.Name, strings.ToLower(string(action))), 107 Namespace: queue.Namespace, 108 OwnerReferences: []metav1.OwnerReference{ 109 *ctrlRef, 110 }, 111 }, 112 TargetObject: ctrlRef, 113 Action: string(action), 114 } 115 116 if _, err := vcClient.BusV1alpha1().Commands(ns).Create(context.TODO(), cmd, metav1.CreateOptions{}); err != nil { 117 return err 118 } 119 120 return nil 121 } 122 123 // CreateJobCommand executes a command such as resume/suspend. 124 func CreateJobCommand(config *rest.Config, ns, name string, action vcbus.Action) error { 125 jobClient := versioned.NewForConfigOrDie(config) 126 job, err := jobClient.BatchV1alpha1().Jobs(ns).Get(context.TODO(), name, metav1.GetOptions{}) 127 if err != nil { 128 return err 129 } 130 131 ctrlRef := metav1.NewControllerRef(job, helpers.JobKind) 132 cmd := &vcbus.Command{ 133 ObjectMeta: metav1.ObjectMeta{ 134 GenerateName: fmt.Sprintf("%s-%s-", 135 job.Name, strings.ToLower(string(action))), 136 Namespace: job.Namespace, 137 OwnerReferences: []metav1.OwnerReference{ 138 *ctrlRef, 139 }, 140 }, 141 TargetObject: ctrlRef, 142 Action: string(action), 143 } 144 145 if _, err := jobClient.BusV1alpha1().Commands(ns).Create(context.TODO(), cmd, metav1.CreateOptions{}); err != nil { 146 return err 147 } 148 149 return nil 150 } 151 152 // TranslateTimestampSince translates the time stamp. 153 func TranslateTimestampSince(timestamp metav1.Time) string { 154 if timestamp.IsZero() { 155 return "<unknown>" 156 } 157 return HumanDuration(time.Since(timestamp.Time)) 158 } 159 160 // HumanDuration translate time.Duration to human readable time string. 161 func HumanDuration(d time.Duration) string { 162 // Allow deviation no more than 2 seconds(excluded) to tolerate machine time 163 // inconsistence, it can be considered as almost now. 164 if seconds := int(d.Seconds()); seconds < -1 { 165 return "<invalid>" 166 } else if seconds < 0 { 167 return "0s" 168 } else if seconds < 60*2 { 169 return fmt.Sprintf("%ds", seconds) 170 } 171 minutes := int(d / time.Minute) 172 if minutes < 10 { 173 s := int(d/time.Second) % 60 174 if s == 0 { 175 return fmt.Sprintf("%dm", minutes) 176 } 177 return fmt.Sprintf("%dm%ds", minutes, s) 178 } else if minutes < 60*3 { 179 return fmt.Sprintf("%dm", minutes) 180 } 181 hours := int(d / time.Hour) 182 if hours < 8 { 183 m := int(d/time.Minute) % 60 184 if m == 0 { 185 return fmt.Sprintf("%dh", hours) 186 } 187 return fmt.Sprintf("%dh%dm", hours, m) 188 } else if hours < 48 { 189 return fmt.Sprintf("%dh", hours) 190 } else if hours < 24*8 { 191 h := hours % 24 192 if h == 0 { 193 return fmt.Sprintf("%dd", hours/24) 194 } 195 return fmt.Sprintf("%dd%dh", hours/24, h) 196 } else if hours < 24*365*2 { 197 return fmt.Sprintf("%dd", hours/24) 198 } else if hours < 24*365*8 { 199 return fmt.Sprintf("%dy%dd", hours/24/365, (hours/24)%365) 200 } 201 return fmt.Sprintf("%dy", hours/24/365) 202 }