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  }