github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/kubectl/version.go (about)

     1  /*
     2  Copyright 2019 The Skaffold 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 kubectl
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"os/exec"
    25  	"strconv"
    26  	"strings"
    27  
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/warnings"
    30  )
    31  
    32  const unknown = "unknown"
    33  
    34  // Version is the client version of kubectl.
    35  type Version struct {
    36  	Client ClientVersion `json:"clientVersion"`
    37  }
    38  
    39  // ClientVersion is the client version of kubectl.
    40  type ClientVersion struct {
    41  	Major string `json:"major"`
    42  	Minor string `json:"minor"`
    43  }
    44  
    45  func (v ClientVersion) String() string {
    46  	if v.Major == unknown || v.Minor == unknown {
    47  		return unknown
    48  	}
    49  
    50  	return v.Major + "." + v.Minor
    51  }
    52  
    53  // CheckVersion warns the user if their kubectl version is < 1.12.0
    54  func (c *CLI) CheckVersion(ctx context.Context) error {
    55  	comp, err := c.CompareVersionTo(ctx, 1, 12)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	if comp < 0 {
    61  		return errors.New("kubectl version 1.12.0 or greater is recommended for use with Skaffold")
    62  	}
    63  	return nil
    64  }
    65  
    66  func (c *CLI) CompareVersionTo(ctx context.Context, vMajor, vMinor int) (int, error) {
    67  	v := c.Version(ctx)
    68  
    69  	majorInt, err := strconv.Atoi(v.Major)
    70  	if err != nil {
    71  		return 0, fmt.Errorf("couldn't get kubectl minor version: %w", err)
    72  	}
    73  
    74  	// Some patched versions get a '+' suffix.
    75  	minorInt, err := strconv.Atoi(strings.TrimRight(v.Minor, "+"))
    76  	if err != nil {
    77  		return 0, fmt.Errorf("couldn't get kubectl minor version: %w", err)
    78  	}
    79  
    80  	if majorInt > vMajor {
    81  		return 1, nil
    82  	}
    83  	if majorInt == vMajor {
    84  		if minorInt > vMinor {
    85  			return 1, nil
    86  		}
    87  		if minorInt == vMinor {
    88  			return 0, nil
    89  		}
    90  	}
    91  
    92  	return -1, nil
    93  }
    94  
    95  // Version returns the client version of kubectl.
    96  func (c *CLI) Version(ctx context.Context) ClientVersion {
    97  	c.versionOnce.Do(func() {
    98  		version := Version{
    99  			Client: ClientVersion{
   100  				Major: unknown,
   101  				Minor: unknown,
   102  			},
   103  		}
   104  
   105  		buf, err := c.getVersion(ctx)
   106  		if err != nil {
   107  			warnings.Printf("unable to get kubectl client version: %v", err)
   108  		} else if err := json.Unmarshal(buf, &version); err != nil {
   109  			warnings.Printf("unable to parse client version: %v", err)
   110  		}
   111  
   112  		c.version = version.Client
   113  	})
   114  
   115  	return c.version
   116  }
   117  
   118  func (c *CLI) getVersion(ctx context.Context) ([]byte, error) {
   119  	cmd := exec.CommandContext(ctx, "kubectl", "version", "--client", "-ojson")
   120  	return util.RunCmdOut(ctx, cmd)
   121  }