mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
vendor update for E2E framework
Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
113
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/arguments.go
generated
vendored
Normal file
113
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/arguments.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// BuildArgumentListFromMap takes two string-string maps, one with the base arguments and one
|
||||
// with optional override arguments. In the return list override arguments will precede base
|
||||
// arguments
|
||||
func BuildArgumentListFromMap(baseArguments map[string]string, overrideArguments map[string]string) []string {
|
||||
var command []string
|
||||
var keys []string
|
||||
|
||||
argsMap := make(map[string]string)
|
||||
|
||||
for k, v := range baseArguments {
|
||||
argsMap[k] = v
|
||||
}
|
||||
|
||||
for k, v := range overrideArguments {
|
||||
argsMap[k] = v
|
||||
}
|
||||
|
||||
for k := range argsMap {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
command = append(command, fmt.Sprintf("--%s=%s", k, argsMap[k]))
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
// ParseArgumentListToMap parses a CLI argument list in the form "--foo=bar" to a string-string map
|
||||
func ParseArgumentListToMap(arguments []string) map[string]string {
|
||||
resultingMap := map[string]string{}
|
||||
for i, arg := range arguments {
|
||||
key, val, err := parseArgument(arg)
|
||||
|
||||
// Ignore if the first argument doesn't satisfy the criteria, it's most often the binary name
|
||||
// Warn in all other cases, but don't error out. This can happen only if the user has edited the argument list by hand, so they might know what they are doing
|
||||
if err != nil {
|
||||
if i != 0 {
|
||||
fmt.Printf("[kubeadm] WARNING: The component argument %q could not be parsed correctly. The argument must be of the form %q. Skipping...", arg, "--")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
resultingMap[key] = val
|
||||
}
|
||||
return resultingMap
|
||||
}
|
||||
|
||||
// ReplaceArgument gets a command list; converts it to a map for easier modification, runs the provided function that
|
||||
// returns a new modified map, and then converts the map back to a command string slice
|
||||
func ReplaceArgument(command []string, argMutateFunc func(map[string]string) map[string]string) []string {
|
||||
argMap := ParseArgumentListToMap(command)
|
||||
|
||||
// Save the first command (the executable) if we're sure it's not an argument (i.e. no --)
|
||||
var newCommand []string
|
||||
if len(command) > 0 && !strings.HasPrefix(command[0], "--") {
|
||||
newCommand = append(newCommand, command[0])
|
||||
}
|
||||
newArgMap := argMutateFunc(argMap)
|
||||
newCommand = append(newCommand, BuildArgumentListFromMap(newArgMap, map[string]string{})...)
|
||||
return newCommand
|
||||
}
|
||||
|
||||
// parseArgument parses the argument "--foo=bar" to "foo" and "bar"
|
||||
func parseArgument(arg string) (string, string, error) {
|
||||
if !strings.HasPrefix(arg, "--") {
|
||||
return "", "", errors.New("the argument should start with '--'")
|
||||
}
|
||||
if !strings.Contains(arg, "=") {
|
||||
return "", "", errors.New("the argument should have a '=' between the flag and the value")
|
||||
}
|
||||
// Remove the starting --
|
||||
arg = strings.TrimPrefix(arg, "--")
|
||||
// Split the string on =. Return only two substrings, since we want only key/value, but the value can include '=' as well
|
||||
keyvalSlice := strings.SplitN(arg, "=", 2)
|
||||
|
||||
// Make sure both a key and value is present
|
||||
if len(keyvalSlice) != 2 {
|
||||
return "", "", errors.New("the argument must have both a key and a value")
|
||||
}
|
||||
if len(keyvalSlice[0]) == 0 {
|
||||
return "", "", errors.New("the argument must have a key")
|
||||
}
|
||||
|
||||
return keyvalSlice[0], keyvalSlice[1], nil
|
||||
}
|
83
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/cgroupdriver.go
generated
vendored
Normal file
83
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/cgroupdriver.go
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
utilsexec "k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
const (
|
||||
// CgroupDriverSystemd holds the systemd driver type
|
||||
CgroupDriverSystemd = "systemd"
|
||||
// CgroupDriverCgroupfs holds the cgroupfs driver type
|
||||
CgroupDriverCgroupfs = "cgroupfs"
|
||||
)
|
||||
|
||||
// TODO: add support for detecting the cgroup driver for CRI other than
|
||||
// Docker. Currently only Docker driver detection is supported:
|
||||
// Discussion:
|
||||
// https://github.com/kubernetes/kubeadm/issues/844
|
||||
|
||||
// GetCgroupDriverDocker runs 'docker info' to obtain the docker cgroup driver
|
||||
func GetCgroupDriverDocker(execer utilsexec.Interface) (string, error) {
|
||||
info, err := callDockerInfo(execer)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return getCgroupDriverFromDockerInfo(info)
|
||||
}
|
||||
|
||||
func validateCgroupDriver(driver string) error {
|
||||
if driver != CgroupDriverCgroupfs && driver != CgroupDriverSystemd {
|
||||
return errors.Errorf("unknown cgroup driver %q", driver)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Docker 1.13 has a new way to obatain the cgroup driver:
|
||||
// docker info -f "{{.CgroupDriver}}
|
||||
// If the minimum supported Docker version in K8s becomes 1.13, move to
|
||||
// this syntax.
|
||||
func callDockerInfo(execer utilsexec.Interface) (string, error) {
|
||||
out, err := execer.Command("docker", "info").Output()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "cannot execute 'docker info'")
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func getCgroupDriverFromDockerInfo(info string) (string, error) {
|
||||
lineSeparator := ": "
|
||||
prefix := "Cgroup Driver"
|
||||
for _, line := range strings.Split(info, "\n") {
|
||||
if !strings.Contains(line, prefix+lineSeparator) {
|
||||
continue
|
||||
}
|
||||
lineSplit := strings.Split(line, lineSeparator)
|
||||
// At this point len(lineSplit) is always >= 2
|
||||
driver := lineSplit[1]
|
||||
if err := validateCgroupDriver(driver); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return driver, nil
|
||||
}
|
||||
return "", errors.New("cgroup driver is not defined in 'docker info'")
|
||||
}
|
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_unix.go
generated
vendored
Normal file
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_unix.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Chroot chroot()s to the new path.
|
||||
// NB: All file paths after this call are effectively relative to
|
||||
// `rootfs`
|
||||
func Chroot(rootfs string) error {
|
||||
if err := syscall.Chroot(rootfs); err != nil {
|
||||
return errors.Wrapf(err, "unable to chroot to %s", rootfs)
|
||||
}
|
||||
root := filepath.FromSlash("/")
|
||||
if err := os.Chdir(root); err != nil {
|
||||
return errors.Wrapf(err, "unable to chdir to %s", root)
|
||||
}
|
||||
return nil
|
||||
}
|
30
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_windows.go
generated
vendored
Normal file
30
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_windows.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Chroot chroot()s to the new path.
|
||||
// NB: All file paths after this call are effectively relative to
|
||||
// `rootfs`
|
||||
func Chroot(rootfs string) error {
|
||||
return errors.New("chroot is not implemented on Windows")
|
||||
}
|
31
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/copy.go
generated
vendored
Normal file
31
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/copy.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// CopyDir copies the content of a folder
|
||||
func CopyDir(src string, dst string) error {
|
||||
cmd := exec.Command("cp", "-r", src, dst)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
124
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint.go
generated
vendored
Normal file
124
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint.go
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
// GetControlPlaneEndpoint returns a properly formatted endpoint for the control plane built according following rules:
|
||||
// - If the controlPlaneEndpoint is defined, use it.
|
||||
// - if the controlPlaneEndpoint is defined but without a port number, use the controlPlaneEndpoint + localEndpoint.BindPort is used.
|
||||
// - Otherwise, in case the controlPlaneEndpoint is not defined, use the localEndpoint.AdvertiseAddress + the localEndpoint.BindPort.
|
||||
func GetControlPlaneEndpoint(controlPlaneEndpoint string, localEndpoint *kubeadmapi.APIEndpoint) (string, error) {
|
||||
// parse the bind port
|
||||
bindPortString := strconv.Itoa(int(localEndpoint.BindPort))
|
||||
if _, err := ParsePort(bindPortString); err != nil {
|
||||
return "", errors.Wrapf(err, "invalid value %q given for api.bindPort", localEndpoint.BindPort)
|
||||
}
|
||||
|
||||
// parse the AdvertiseAddress
|
||||
var ip = net.ParseIP(localEndpoint.AdvertiseAddress)
|
||||
if ip == nil {
|
||||
return "", errors.Errorf("invalid value `%s` given for api.advertiseAddress", localEndpoint.AdvertiseAddress)
|
||||
}
|
||||
|
||||
// set the control-plane url using localEndpoint.AdvertiseAddress + the localEndpoint.BindPort
|
||||
controlPlaneURL := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: net.JoinHostPort(ip.String(), bindPortString),
|
||||
}
|
||||
|
||||
// if the controlplane endpoint is defined
|
||||
if len(controlPlaneEndpoint) > 0 {
|
||||
// parse the controlplane endpoint
|
||||
var host, port string
|
||||
var err error
|
||||
if host, port, err = ParseHostPort(controlPlaneEndpoint); err != nil {
|
||||
return "", errors.Wrapf(err, "invalid value %q given for controlPlaneEndpoint", controlPlaneEndpoint)
|
||||
}
|
||||
|
||||
// if a port is provided within the controlPlaneAddress warn the users we are using it, else use the bindport
|
||||
if port != "" {
|
||||
if port != bindPortString {
|
||||
fmt.Println("[endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address")
|
||||
}
|
||||
} else {
|
||||
port = bindPortString
|
||||
}
|
||||
|
||||
// overrides the control-plane url using the controlPlaneAddress (and eventually the bindport)
|
||||
controlPlaneURL = &url.URL{
|
||||
Scheme: "https",
|
||||
Host: net.JoinHostPort(host, port),
|
||||
}
|
||||
}
|
||||
|
||||
return controlPlaneURL.String(), nil
|
||||
}
|
||||
|
||||
// ParseHostPort parses a network address of the form "host:port", "ipv4:port", "[ipv6]:port" into host and port;
|
||||
// ":port" can be eventually omitted.
|
||||
// If the string is not a valid representation of network address, ParseHostPort returns an error.
|
||||
func ParseHostPort(hostport string) (string, string, error) {
|
||||
var host, port string
|
||||
var err error
|
||||
|
||||
// try to split host and port
|
||||
if host, port, err = net.SplitHostPort(hostport); err != nil {
|
||||
// if SplitHostPort returns an error, the entire hostport is considered as host
|
||||
host = hostport
|
||||
}
|
||||
|
||||
// if port is defined, parse and validate it
|
||||
if port != "" {
|
||||
if _, err := ParsePort(port); err != nil {
|
||||
return "", "", errors.Errorf("hostport %s: port %s must be a valid number between 1 and 65535, inclusive", hostport, port)
|
||||
}
|
||||
}
|
||||
|
||||
// if host is a valid IP, returns it
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
return host, port, nil
|
||||
}
|
||||
|
||||
// if host is a validate RFC-1123 subdomain, returns it
|
||||
if errs := validation.IsDNS1123Subdomain(host); len(errs) == 0 {
|
||||
return host, port, nil
|
||||
}
|
||||
|
||||
return "", "", errors.Errorf("hostport %s: host '%s' must be a valid IP address or a valid RFC-1123 DNS subdomain", hostport, host)
|
||||
}
|
||||
|
||||
// ParsePort parses a string representing a TCP port.
|
||||
// If the string is not a valid representation of a TCP port, ParsePort returns an error.
|
||||
func ParsePort(port string) (int, error) {
|
||||
portInt, err := strconv.Atoi(port)
|
||||
if err == nil && (1 <= portInt && portInt <= 65535) {
|
||||
return portInt, nil
|
||||
}
|
||||
|
||||
return 0, errors.New("port must be a valid number between 1 and 65535, inclusive")
|
||||
}
|
87
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/error.go
generated
vendored
Normal file
87
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/error.go
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
errorsutil "k8s.io/apimachinery/pkg/util/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultErrorExitCode defines exit the code for failed action generally
|
||||
DefaultErrorExitCode = 1
|
||||
// PreFlightExitCode defines exit the code for preflight checks
|
||||
PreFlightExitCode = 2
|
||||
// ValidationExitCode defines the exit code validation checks
|
||||
ValidationExitCode = 3
|
||||
)
|
||||
|
||||
// fatal prints the message if set and then exits.
|
||||
func fatal(msg string, code int) {
|
||||
if len(msg) > 0 {
|
||||
// add newline if needed
|
||||
if !strings.HasSuffix(msg, "\n") {
|
||||
msg += "\n"
|
||||
}
|
||||
|
||||
fmt.Fprint(os.Stderr, msg)
|
||||
}
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// CheckErr prints a user friendly error to STDERR and exits with a non-zero
|
||||
// exit code. Unrecognized errors will be printed with an "error: " prefix.
|
||||
//
|
||||
// This method is generic to the command in use and may be used by non-Kubectl
|
||||
// commands.
|
||||
func CheckErr(err error) {
|
||||
checkErr(err, fatal)
|
||||
}
|
||||
|
||||
// preflightError allows us to know if the error is a preflight error or not
|
||||
// defining the interface here avoids an import cycle of pulling in preflight into the util package
|
||||
type preflightError interface {
|
||||
Preflight() bool
|
||||
}
|
||||
|
||||
// checkErr formats a given error as a string and calls the passed handleErr
|
||||
// func with that string and an exit code.
|
||||
func checkErr(err error, handleErr func(string, int)) {
|
||||
switch err.(type) {
|
||||
case nil:
|
||||
return
|
||||
case preflightError:
|
||||
handleErr(err.Error(), PreFlightExitCode)
|
||||
case errorsutil.Aggregate:
|
||||
handleErr(err.Error(), ValidationExitCode)
|
||||
|
||||
default:
|
||||
handleErr(err.Error(), DefaultErrorExitCode)
|
||||
}
|
||||
}
|
||||
|
||||
// FormatErrMsg returns a human-readable string describing the slice of errors passed to the function
|
||||
func FormatErrMsg(errs []error) string {
|
||||
var errMsg string
|
||||
for _, err := range errs {
|
||||
errMsg = fmt.Sprintf("%s\t- %s\n", errMsg, err.Error())
|
||||
}
|
||||
return errMsg
|
||||
}
|
163
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal.go
generated
vendored
Normal file
163
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal.go
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
errorsutil "k8s.io/apimachinery/pkg/util/errors"
|
||||
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
// MarshalToYaml marshals an object into yaml.
|
||||
func MarshalToYaml(obj runtime.Object, gv schema.GroupVersion) ([]byte, error) {
|
||||
return MarshalToYamlForCodecs(obj, gv, clientsetscheme.Codecs)
|
||||
}
|
||||
|
||||
// MarshalToYamlForCodecs marshals an object into yaml using the specified codec
|
||||
// TODO: Is specifying the gv really needed here?
|
||||
// TODO: Can we support json out of the box easily here?
|
||||
func MarshalToYamlForCodecs(obj runtime.Object, gv schema.GroupVersion, codecs serializer.CodecFactory) ([]byte, error) {
|
||||
mediaType := "application/yaml"
|
||||
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
|
||||
if !ok {
|
||||
return []byte{}, errors.Errorf("unsupported media type %q", mediaType)
|
||||
}
|
||||
|
||||
encoder := codecs.EncoderForVersion(info.Serializer, gv)
|
||||
return runtime.Encode(encoder, obj)
|
||||
}
|
||||
|
||||
// UnmarshalFromYaml unmarshals yaml into an object.
|
||||
func UnmarshalFromYaml(buffer []byte, gv schema.GroupVersion) (runtime.Object, error) {
|
||||
return UnmarshalFromYamlForCodecs(buffer, gv, clientsetscheme.Codecs)
|
||||
}
|
||||
|
||||
// UnmarshalFromYamlForCodecs unmarshals yaml into an object using the specified codec
|
||||
// TODO: Is specifying the gv really needed here?
|
||||
// TODO: Can we support json out of the box easily here?
|
||||
func UnmarshalFromYamlForCodecs(buffer []byte, gv schema.GroupVersion, codecs serializer.CodecFactory) (runtime.Object, error) {
|
||||
mediaType := "application/yaml"
|
||||
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("unsupported media type %q", mediaType)
|
||||
}
|
||||
|
||||
decoder := codecs.DecoderToVersion(info.Serializer, gv)
|
||||
return runtime.Decode(decoder, buffer)
|
||||
}
|
||||
|
||||
// SplitYAMLDocuments reads the YAML bytes per-document, unmarshals the TypeMeta information from each document
|
||||
// and returns a map between the GroupVersionKind of the document and the document bytes
|
||||
func SplitYAMLDocuments(yamlBytes []byte) (map[schema.GroupVersionKind][]byte, error) {
|
||||
gvkmap := map[schema.GroupVersionKind][]byte{}
|
||||
knownKinds := map[string]bool{}
|
||||
errs := []error{}
|
||||
buf := bytes.NewBuffer(yamlBytes)
|
||||
reader := utilyaml.NewYAMLReader(bufio.NewReader(buf))
|
||||
for {
|
||||
typeMetaInfo := runtime.TypeMeta{}
|
||||
// Read one YAML document at a time, until io.EOF is returned
|
||||
b, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(b) == 0 {
|
||||
break
|
||||
}
|
||||
// Deserialize the TypeMeta information of this byte slice
|
||||
if err := yaml.Unmarshal(b, &typeMetaInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Require TypeMeta information to be present
|
||||
if len(typeMetaInfo.APIVersion) == 0 || len(typeMetaInfo.Kind) == 0 {
|
||||
errs = append(errs, errors.New("invalid configuration: kind and apiVersion is mandatory information that needs to be specified in all YAML documents"))
|
||||
continue
|
||||
}
|
||||
// Check whether the kind has been registered before. If it has, throw an error
|
||||
if known := knownKinds[typeMetaInfo.Kind]; known {
|
||||
errs = append(errs, errors.Errorf("invalid configuration: kind %q is specified twice in YAML file", typeMetaInfo.Kind))
|
||||
continue
|
||||
}
|
||||
knownKinds[typeMetaInfo.Kind] = true
|
||||
|
||||
// Build a GroupVersionKind object from the deserialized TypeMeta object
|
||||
gv, err := schema.ParseGroupVersion(typeMetaInfo.APIVersion)
|
||||
if err != nil {
|
||||
errs = append(errs, errors.Wrap(err, "unable to parse apiVersion"))
|
||||
continue
|
||||
}
|
||||
gvk := gv.WithKind(typeMetaInfo.Kind)
|
||||
|
||||
// Save the mapping between the gvk and the bytes that object consists of
|
||||
gvkmap[gvk] = b
|
||||
}
|
||||
if err := errorsutil.NewAggregate(errs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gvkmap, nil
|
||||
}
|
||||
|
||||
// GroupVersionKindsFromBytes parses the bytes and returns a gvk slice
|
||||
func GroupVersionKindsFromBytes(b []byte) ([]schema.GroupVersionKind, error) {
|
||||
gvkmap, err := SplitYAMLDocuments(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gvks := []schema.GroupVersionKind{}
|
||||
for gvk := range gvkmap {
|
||||
gvks = append(gvks, gvk)
|
||||
}
|
||||
return gvks, nil
|
||||
}
|
||||
|
||||
// GroupVersionKindsHasKind returns whether the following gvk slice contains the kind given as a parameter
|
||||
func GroupVersionKindsHasKind(gvks []schema.GroupVersionKind, kind string) bool {
|
||||
for _, gvk := range gvks {
|
||||
if gvk.Kind == kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GroupVersionKindsHasClusterConfiguration returns whether the following gvk slice contains a ClusterConfiguration object
|
||||
func GroupVersionKindsHasClusterConfiguration(gvks ...schema.GroupVersionKind) bool {
|
||||
return GroupVersionKindsHasKind(gvks, constants.ClusterConfigurationKind)
|
||||
}
|
||||
|
||||
// GroupVersionKindsHasInitConfiguration returns whether the following gvk slice contains a InitConfiguration object
|
||||
func GroupVersionKindsHasInitConfiguration(gvks ...schema.GroupVersionKind) bool {
|
||||
return GroupVersionKindsHasKind(gvks, constants.InitConfigurationKind)
|
||||
}
|
||||
|
||||
// GroupVersionKindsHasJoinConfiguration returns whether the following gvk slice contains a JoinConfiguration object
|
||||
func GroupVersionKindsHasJoinConfiguration(gvks ...schema.GroupVersionKind) bool {
|
||||
return GroupVersionKindsHasKind(gvks, constants.JoinConfigurationKind)
|
||||
}
|
38
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/template.go
generated
vendored
Normal file
38
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/template.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"text/template"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ParseTemplate validates and parses passed as argument template
|
||||
func ParseTemplate(strtmpl string, obj interface{}) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
tmpl, err := template.New("template").Parse(strtmpl)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error when parsing template")
|
||||
}
|
||||
err = tmpl.Execute(&buf, obj)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error when executing template")
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
244
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version.go
generated
vendored
Normal file
244
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version.go
generated
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
netutil "k8s.io/apimachinery/pkg/util/net"
|
||||
versionutil "k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/klog"
|
||||
pkgversion "k8s.io/kubernetes/pkg/version"
|
||||
)
|
||||
|
||||
const (
|
||||
getReleaseVersionTimeout = time.Duration(10 * time.Second)
|
||||
)
|
||||
|
||||
var (
|
||||
kubeReleaseBucketURL = "https://dl.k8s.io"
|
||||
kubeReleaseRegex = regexp.MustCompile(`^v?(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)([-0-9a-zA-Z_\.+]*)?$`)
|
||||
kubeReleaseLabelRegex = regexp.MustCompile(`^[[:lower:]]+(-[-\w_\.]+)?$`)
|
||||
kubeBucketPrefixes = regexp.MustCompile(`^((release|ci|ci-cross)/)?([-\w_\.+]+)$`)
|
||||
)
|
||||
|
||||
// KubernetesReleaseVersion is helper function that can fetch
|
||||
// available version information from release servers based on
|
||||
// label names, like "stable" or "latest".
|
||||
//
|
||||
// If argument is already semantic version string, it
|
||||
// will return same string.
|
||||
//
|
||||
// In case of labels, it tries to fetch from release
|
||||
// servers and then return actual semantic version.
|
||||
//
|
||||
// Available names on release servers:
|
||||
// stable (latest stable release)
|
||||
// stable-1 (latest stable release in 1.x)
|
||||
// stable-1.0 (and similarly 1.1, 1.2, 1.3, ...)
|
||||
// latest (latest release, including alpha/beta)
|
||||
// latest-1 (latest release in 1.x, including alpha/beta)
|
||||
// latest-1.0 (and similarly 1.1, 1.2, 1.3, ...)
|
||||
func KubernetesReleaseVersion(version string) (string, error) {
|
||||
ver := normalizedBuildVersion(version)
|
||||
if len(ver) != 0 {
|
||||
return ver, nil
|
||||
}
|
||||
|
||||
bucketURL, versionLabel, err := splitVersion(version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// revalidate, if exact build from e.g. CI bucket requested.
|
||||
ver = normalizedBuildVersion(versionLabel)
|
||||
if len(ver) != 0 {
|
||||
return ver, nil
|
||||
}
|
||||
|
||||
// kubeReleaseLabelRegex matches labels such as: latest, latest-1, latest-1.10
|
||||
if kubeReleaseLabelRegex.MatchString(versionLabel) {
|
||||
// Try to obtain a client version.
|
||||
// pkgversion.Get().String() should always return a correct version added by the golang
|
||||
// linker and the build system. The version can still be missing when doing unit tests
|
||||
// on individual packages.
|
||||
clientVersion, clientVersionErr := kubeadmVersion(pkgversion.Get().String())
|
||||
// Fetch version from the internet.
|
||||
url := fmt.Sprintf("%s/%s.txt", bucketURL, versionLabel)
|
||||
body, err := fetchFromURL(url, getReleaseVersionTimeout)
|
||||
if err != nil {
|
||||
// If the network operaton was successful but the server did not reply with StatusOK
|
||||
if body != "" {
|
||||
return "", err
|
||||
}
|
||||
// Handle air-gapped environments by falling back to the client version.
|
||||
klog.Infof("could not fetch a Kubernetes version from the internet: %v", err)
|
||||
klog.Infof("falling back to the local client version: %s", clientVersion)
|
||||
return KubernetesReleaseVersion(clientVersion)
|
||||
}
|
||||
|
||||
if clientVersionErr != nil {
|
||||
klog.Warningf("could not obtain client version; using remote version: %s", body)
|
||||
return KubernetesReleaseVersion(body)
|
||||
}
|
||||
|
||||
// both the client and the remote version are obtained; validate them and pick a stable version
|
||||
body, err = validateStableVersion(body, clientVersion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Re-validate received version and return.
|
||||
return KubernetesReleaseVersion(body)
|
||||
}
|
||||
return "", errors.Errorf("version %q doesn't match patterns for neither semantic version nor labels (stable, latest, ...)", version)
|
||||
}
|
||||
|
||||
// KubernetesVersionToImageTag is helper function that replaces all
|
||||
// non-allowed symbols in tag strings with underscores.
|
||||
// Image tag can only contain lowercase and uppercase letters, digits,
|
||||
// underscores, periods and dashes.
|
||||
// Current usage is for CI images where all of symbols except '+' are valid,
|
||||
// but function is for generic usage where input can't be always pre-validated.
|
||||
func KubernetesVersionToImageTag(version string) string {
|
||||
allowed := regexp.MustCompile(`[^-a-zA-Z0-9_\.]`)
|
||||
return allowed.ReplaceAllString(version, "_")
|
||||
}
|
||||
|
||||
// KubernetesIsCIVersion checks if user requested CI version
|
||||
func KubernetesIsCIVersion(version string) bool {
|
||||
subs := kubeBucketPrefixes.FindAllStringSubmatch(version, 1)
|
||||
if len(subs) == 1 && len(subs[0]) == 4 && strings.HasPrefix(subs[0][2], "ci") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Internal helper: returns normalized build version (with "v" prefix if needed)
|
||||
// If input doesn't match known version pattern, returns empty string.
|
||||
func normalizedBuildVersion(version string) string {
|
||||
if kubeReleaseRegex.MatchString(version) {
|
||||
if strings.HasPrefix(version, "v") {
|
||||
return version
|
||||
}
|
||||
return "v" + version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Internal helper: split version parts,
|
||||
// Return base URL and cleaned-up version
|
||||
func splitVersion(version string) (string, string, error) {
|
||||
var urlSuffix string
|
||||
subs := kubeBucketPrefixes.FindAllStringSubmatch(version, 1)
|
||||
if len(subs) != 1 || len(subs[0]) != 4 {
|
||||
return "", "", errors.Errorf("invalid version %q", version)
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(subs[0][2], "ci"):
|
||||
// Just use whichever the user specified
|
||||
urlSuffix = subs[0][2]
|
||||
default:
|
||||
urlSuffix = "release"
|
||||
}
|
||||
url := fmt.Sprintf("%s/%s", kubeReleaseBucketURL, urlSuffix)
|
||||
return url, subs[0][3], nil
|
||||
}
|
||||
|
||||
// Internal helper: return content of URL
|
||||
func fetchFromURL(url string, timeout time.Duration) (string, error) {
|
||||
klog.V(2).Infof("fetching Kubernetes version from URL: %s", url)
|
||||
client := &http.Client{Timeout: timeout, Transport: netutil.SetOldTransportDefaults(&http.Transport{})}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("unable to get URL %q: %s", url, err.Error())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("unable to read content of URL %q: %s", url, err.Error())
|
||||
}
|
||||
bodyString := strings.TrimSpace(string(body))
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
msg := fmt.Sprintf("unable to fetch file. URL: %q, status: %v", url, resp.Status)
|
||||
return bodyString, errors.New(msg)
|
||||
}
|
||||
return bodyString, nil
|
||||
}
|
||||
|
||||
// kubeadmVersion returns the version of the client without metadata.
|
||||
func kubeadmVersion(info string) (string, error) {
|
||||
v, err := versionutil.ParseSemantic(info)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "kubeadm version error")
|
||||
}
|
||||
// There is no utility in versionutil to get the version without the metadata,
|
||||
// so this needs some manual formatting.
|
||||
// Discard offsets after a release label and keep the labels down to e.g. `alpha.0` instead of
|
||||
// including the offset e.g. `alpha.0.206`. This is done to comply with GCR image tags.
|
||||
pre := v.PreRelease()
|
||||
patch := v.Patch()
|
||||
if len(pre) > 0 {
|
||||
if patch > 0 {
|
||||
// If the patch version is more than zero, decrement it and remove the label.
|
||||
// this is done to comply with the latest stable patch release.
|
||||
patch = patch - 1
|
||||
pre = ""
|
||||
} else {
|
||||
split := strings.Split(pre, ".")
|
||||
if len(split) > 2 {
|
||||
pre = split[0] + "." + split[1] // Exclude the third element
|
||||
} else if len(split) < 2 {
|
||||
pre = split[0] + ".0" // Append .0 to a partial label
|
||||
}
|
||||
pre = "-" + pre
|
||||
}
|
||||
}
|
||||
vStr := fmt.Sprintf("v%d.%d.%d%s", v.Major(), v.Minor(), patch, pre)
|
||||
return vStr, nil
|
||||
}
|
||||
|
||||
// Validate if the remote version is one Minor release newer than the client version.
|
||||
// This is done to conform with "stable-X" and only allow remote versions from
|
||||
// the same Patch level release.
|
||||
func validateStableVersion(remoteVersion, clientVersion string) (string, error) {
|
||||
verRemote, err := versionutil.ParseGeneric(remoteVersion)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "remote version error")
|
||||
}
|
||||
verClient, err := versionutil.ParseGeneric(clientVersion)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "client version error")
|
||||
}
|
||||
// If the remote Major version is bigger or if the Major versions are the same,
|
||||
// but the remote Minor is bigger use the client version release. This handles Major bumps too.
|
||||
if verClient.Major() < verRemote.Major() ||
|
||||
(verClient.Major() == verRemote.Major()) && verClient.Minor() < verRemote.Minor() {
|
||||
estimatedRelease := fmt.Sprintf("stable-%d.%d", verClient.Major(), verClient.Minor())
|
||||
klog.Infof("remote version is much newer: %s; falling back to: %s", remoteVersion, estimatedRelease)
|
||||
return estimatedRelease, nil
|
||||
}
|
||||
return remoteVersion, nil
|
||||
}
|
Reference in New Issue
Block a user