update vendor

Signed-off-by: Roland.Ma <rolandma@yunify.com>
This commit is contained in:
Roland.Ma
2021-08-11 07:10:14 +00:00
parent a18f72b565
commit ea8f47c73a
2901 changed files with 269317 additions and 43103 deletions

View File

@@ -20,12 +20,16 @@ import (
"bufio"
"bytes"
"context"
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"time"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -34,18 +38,31 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/util/retry"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/conversion"
"sigs.k8s.io/yaml"
)
// CRDInstallOptions are the options for installing CRDs
// CRDInstallOptions are the options for installing CRDs.
type CRDInstallOptions struct {
// Scheme is used to determine if conversion webhooks should be enabled
// for a particular CRD / object.
//
// Conversion webhooks are going to be enabled if an object in the scheme
// implements Hub and Spoke conversions.
//
// If nil, scheme.Scheme is used.
Scheme *runtime.Scheme
// Paths is a list of paths to the directories or files containing CRDs
Paths []string
// CRDs is a list of CRDs to install
CRDs []runtime.Object
CRDs []client.Object
// ErrorIfPathMissing will cause an error if a Path does not exist
ErrorIfPathMissing bool
@@ -60,34 +77,45 @@ type CRDInstallOptions struct {
// uninstalled when terminating the test environment.
// Defaults to false.
CleanUpAfterUse bool
// WebhookOptions contains the conversion webhook information to install
// on the CRDs. This field is usually inherited by the EnvTest options.
//
// If you're passing this field manually, you need to make sure that
// the CA information and host port is filled in properly.
WebhookOptions WebhookInstallOptions
}
const defaultPollInterval = 100 * time.Millisecond
const defaultMaxWait = 10 * time.Second
// InstallCRDs installs a collection of CRDs into a cluster by reading the crd yaml files from a directory
func InstallCRDs(config *rest.Config, options CRDInstallOptions) ([]runtime.Object, error) {
// InstallCRDs installs a collection of CRDs into a cluster by reading the crd yaml files from a directory.
func InstallCRDs(config *rest.Config, options CRDInstallOptions) ([]client.Object, error) {
defaultCRDOptions(&options)
// Read the CRD yamls into options.CRDs
if err := readCRDFiles(&options); err != nil {
return nil, fmt.Errorf("unable to read CRD files: %w", err)
}
if err := modifyConversionWebhooks(options.CRDs, options.Scheme, options.WebhookOptions); err != nil {
return nil, err
}
// Create the CRDs in the apiserver
if err := CreateCRDs(config, options.CRDs); err != nil {
return options.CRDs, err
return options.CRDs, fmt.Errorf("unable to create CRD instances: %w", err)
}
// Wait for the CRDs to appear as Resources in the apiserver
if err := WaitForCRDs(config, options.CRDs, options); err != nil {
return options.CRDs, err
return options.CRDs, fmt.Errorf("something went wrong waiting for CRDs to appear as API resources: %w", err)
}
return options.CRDs, nil
}
// readCRDFiles reads the directories of CRDs in options.Paths and adds the CRD structs to options.CRDs
// readCRDFiles reads the directories of CRDs in options.Paths and adds the CRD structs to options.CRDs.
func readCRDFiles(options *CRDInstallOptions) error {
if len(options.Paths) > 0 {
crdList, err := renderCRDs(options)
@@ -100,8 +128,11 @@ func readCRDFiles(options *CRDInstallOptions) error {
return nil
}
// defaultCRDOptions sets the default values for CRDs
// defaultCRDOptions sets the default values for CRDs.
func defaultCRDOptions(o *CRDInstallOptions) {
if o.Scheme == nil {
o.Scheme = scheme.Scheme
}
if o.MaxTime == 0 {
o.MaxTime = defaultMaxWait
}
@@ -110,8 +141,8 @@ func defaultCRDOptions(o *CRDInstallOptions) {
}
}
// WaitForCRDs waits for the CRDs to appear in discovery
func WaitForCRDs(config *rest.Config, crds []runtime.Object, options CRDInstallOptions) error {
// WaitForCRDs waits for the CRDs to appear in discovery.
func WaitForCRDs(config *rest.Config, crds []client.Object, options CRDInstallOptions) error {
// Add each CRD to a map of GroupVersion to Resource
waitingFor := map[schema.GroupVersion]*sets.String{}
for _, crd := range runtimeCRDListToUnstructured(crds) {
@@ -128,14 +159,17 @@ func WaitForCRDs(config *rest.Config, crds []runtime.Object, options CRDInstallO
if err != nil {
return err
}
if crdVersion != "" {
gvs = append(gvs, schema.GroupVersion{Group: crdGroup, Version: crdVersion})
}
versions, _, err := unstructured.NestedSlice(crd.Object, "spec", "versions")
versions, found, err := unstructured.NestedSlice(crd.Object, "spec", "versions")
if err != nil {
return err
}
// gvs should be added here only if single version is found. If multiple version is found we will add those version
// based on the version is served or not.
if crdVersion != "" && !found {
gvs = append(gvs, schema.GroupVersion{Group: crdGroup, Version: crdVersion})
}
for _, version := range versions {
versionMap, ok := version.(map[string]interface{})
if !ok {
@@ -170,7 +204,7 @@ func WaitForCRDs(config *rest.Config, crds []runtime.Object, options CRDInstallO
return wait.PollImmediate(options.PollInterval, options.MaxTime, p.poll)
}
// poller checks if all the resources have been found in discovery, and returns false if not
// poller checks if all the resources have been found in discovery, and returns false if not.
type poller struct {
// config is used to get discovery
config *rest.Config
@@ -179,7 +213,7 @@ type poller struct {
waitingFor map[schema.GroupVersion]*sets.String
}
// poll checks if all the resources have been found in discovery, and returns false if not
// poll checks if all the resources have been found in discovery, and returns false if not.
func (p *poller) poll() (done bool, err error) {
// Create a new clientset to avoid any client caching of discovery
cs, err := clientset.NewForConfig(p.config)
@@ -199,7 +233,7 @@ func (p *poller) poll() (done bool, err error) {
// TODO: Maybe the controller-runtime client should be able to do this...
resourceList, err := cs.Discovery().ServerResourcesForGroupVersion(gv.Group + "/" + gv.Version)
if err != nil {
return false, nil
return false, nil //nolint:nilerr
}
// Remove each found resource from the resources set that we are waiting for
@@ -215,9 +249,8 @@ func (p *poller) poll() (done bool, err error) {
return allFound, nil
}
// UninstallCRDs uninstalls a collection of CRDs by reading the crd yaml files from a directory
// UninstallCRDs uninstalls a collection of CRDs by reading the crd yaml files from a directory.
func UninstallCRDs(config *rest.Config, options CRDInstallOptions) error {
// Read the CRD yamls into options.CRDs
if err := readCRDFiles(&options); err != nil {
return err
@@ -243,11 +276,11 @@ func UninstallCRDs(config *rest.Config, options CRDInstallOptions) error {
return nil
}
// CreateCRDs creates the CRDs
func CreateCRDs(config *rest.Config, crds []runtime.Object) error {
// CreateCRDs creates the CRDs.
func CreateCRDs(config *rest.Config, crds []client.Object) error {
cs, err := client.New(config, client.Options{})
if err != nil {
return err
return fmt.Errorf("unable to create client: %w", err)
}
// Create each CRD
@@ -258,14 +291,19 @@ func CreateCRDs(config *rest.Config, crds []runtime.Object) error {
switch {
case apierrors.IsNotFound(err):
if err := cs.Create(context.TODO(), crd); err != nil {
return err
return fmt.Errorf("unable to create CRD %q: %w", crd.GetName(), err)
}
case err != nil:
return err
return fmt.Errorf("unable to get CRD %q to check if it exists: %w", crd.GetName(), err)
default:
log.V(1).Info("CRD already exists, updating", "crd", crd.GetName())
crd.SetResourceVersion(existingCrd.GetResourceVersion())
if err := cs.Update(context.TODO(), crd); err != nil {
if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
if err := cs.Get(context.TODO(), client.ObjectKey{Name: crd.GetName()}, existingCrd); err != nil {
return err
}
crd.SetResourceVersion(existingCrd.GetResourceVersion())
return cs.Update(context.TODO(), crd)
}); err != nil {
return err
}
}
@@ -274,7 +312,7 @@ func CreateCRDs(config *rest.Config, crds []runtime.Object) error {
}
// renderCRDs iterate through options.Paths and extract all CRD files.
func renderCRDs(options *CRDInstallOptions) ([]runtime.Object, error) {
func renderCRDs(options *CRDInstallOptions) ([]client.Object, error) {
var (
err error
info os.FileInfo
@@ -301,10 +339,8 @@ func renderCRDs(options *CRDInstallOptions) ([]runtime.Object, error) {
if !info.IsDir() {
filePath, files = filepath.Dir(path), []os.FileInfo{info}
} else {
if files, err = ioutil.ReadDir(path); err != nil {
return nil, err
}
} else if files, err = ioutil.ReadDir(path); err != nil {
return nil, err
}
log.V(1).Info("reading CRDs from path", "path", path)
@@ -325,14 +361,200 @@ func renderCRDs(options *CRDInstallOptions) ([]runtime.Object, error) {
}
// Converting map to a list to return
var res []runtime.Object
res := []client.Object{}
for _, obj := range crds {
res = append(res, obj)
}
return res, nil
}
// readCRDs reads the CRDs from files and Unmarshals them into structs
// modifyConversionWebhooks takes all the registered CustomResourceDefinitions and applies modifications
// to conditionally enable webhooks if the type is registered within the scheme.
//
// The complexity of this function is high mostly due to all the edge cases that we need to handle:
// CRDv1beta1, CRDv1, and their unstructured counterpart.
//
// We should be able to simplify this code once we drop support for v1beta1 and standardize around the typed CRDv1 object.
func modifyConversionWebhooks(crds []client.Object, scheme *runtime.Scheme, webhookOptions WebhookInstallOptions) error { //nolint:gocyclo
if len(webhookOptions.LocalServingCAData) == 0 {
return nil
}
// Determine all registered convertible types.
convertibles := map[schema.GroupKind]struct{}{}
for gvk := range scheme.AllKnownTypes() {
obj, err := scheme.New(gvk)
if err != nil {
return err
}
if ok, err := conversion.IsConvertible(scheme, obj); ok && err == nil {
convertibles[gvk.GroupKind()] = struct{}{}
}
}
// generate host port.
hostPort, err := webhookOptions.generateHostPort()
if err != nil {
return err
}
url := pointer.StringPtr(fmt.Sprintf("https://%s/convert", hostPort))
for _, crd := range crds {
switch c := crd.(type) {
case *apiextensionsv1beta1.CustomResourceDefinition:
// Continue if we're preserving unknown fields.
//
// preserveUnknownFields defaults to true if `nil` in v1beta1.
if c.Spec.PreserveUnknownFields == nil || *c.Spec.PreserveUnknownFields {
continue
}
// Continue if the GroupKind isn't registered as being convertible.
if _, ok := convertibles[schema.GroupKind{
Group: c.Spec.Group,
Kind: c.Spec.Names.Kind,
}]; !ok {
continue
}
c.Spec.Conversion.Strategy = apiextensionsv1beta1.WebhookConverter
c.Spec.Conversion.WebhookClientConfig.Service = nil
c.Spec.Conversion.WebhookClientConfig = &apiextensionsv1beta1.WebhookClientConfig{
Service: nil,
URL: url,
CABundle: webhookOptions.LocalServingCAData,
}
case *apiextensionsv1.CustomResourceDefinition:
// Continue if we're preserving unknown fields.
if c.Spec.PreserveUnknownFields {
continue
}
// Continue if the GroupKind isn't registered as being convertible.
if _, ok := convertibles[schema.GroupKind{
Group: c.Spec.Group,
Kind: c.Spec.Names.Kind,
}]; !ok {
continue
}
c.Spec.Conversion.Strategy = apiextensionsv1.WebhookConverter
c.Spec.Conversion.Webhook.ClientConfig.Service = nil
c.Spec.Conversion.Webhook.ClientConfig = &apiextensionsv1.WebhookClientConfig{
Service: nil,
URL: url,
CABundle: webhookOptions.LocalServingCAData,
}
case *unstructured.Unstructured:
webhookClientConfig := map[string]interface{}{
"url": *url,
"caBundle": base64.StdEncoding.EncodeToString(webhookOptions.LocalServingCAData),
}
switch c.GroupVersionKind().Version {
case "v1beta1":
// Continue if we're preserving unknown fields.
//
// preserveUnknownFields defaults to true if `nil` in v1beta1.
if preserve, found, err := unstructured.NestedBool(c.Object, "spec", "preserveUnknownFields"); preserve || !found {
continue
} else if err != nil {
return err
}
// Continue if the GroupKind isn't registered as being convertible.
group, found, err := unstructured.NestedString(c.Object, "spec", "group")
if !found {
continue
} else if err != nil {
return err
}
kind, found, err := unstructured.NestedString(c.Object, "spec", "names", "kind")
if !found {
continue
} else if err != nil {
return err
}
if _, ok := convertibles[schema.GroupKind{
Group: group,
Kind: kind,
}]; !ok {
continue
}
// Set the strategy.
if err := unstructured.SetNestedField(
c.Object,
string(apiextensionsv1beta1.WebhookConverter),
"spec", "conversion", "strategy"); err != nil {
return err
}
// Set the conversion review versions.
if err := unstructured.SetNestedStringSlice(
c.Object,
[]string{"v1beta1"},
"spec", "conversion", "webhook", "clientConfig"); err != nil {
return err
}
// Set the client configuration.
if err := unstructured.SetNestedMap(
c.Object,
webhookClientConfig,
"spec", "conversion", "webhookClientConfig"); err != nil {
return err
}
case "v1":
if preserve, _, err := unstructured.NestedBool(c.Object, "spec", "preserveUnknownFields"); preserve {
continue
} else if err != nil {
return err
}
// Continue if the GroupKind isn't registered as being convertible.
group, found, err := unstructured.NestedString(c.Object, "spec", "group")
if !found {
continue
} else if err != nil {
return err
}
kind, found, err := unstructured.NestedString(c.Object, "spec", "names", "kind")
if !found {
continue
} else if err != nil {
return err
}
if _, ok := convertibles[schema.GroupKind{
Group: group,
Kind: kind,
}]; !ok {
continue
}
// Set the strategy.
if err := unstructured.SetNestedField(
c.Object,
string(apiextensionsv1.WebhookConverter),
"spec", "conversion", "strategy"); err != nil {
return err
}
// Set the conversion review versions.
if err := unstructured.SetNestedStringSlice(
c.Object,
[]string{"v1", "v1beta1"},
"spec", "conversion", "webhook", "conversionReviewVersions"); err != nil {
return err
}
// Set the client configuration.
if err := unstructured.SetNestedMap(
c.Object,
webhookClientConfig,
"spec", "conversion", "webhook", "clientConfig"); err != nil {
return err
}
}
}
}
return nil
}
// readCRDs reads the CRDs from files and Unmarshals them into structs.
func readCRDs(basePath string, files []os.FileInfo) ([]*unstructured.Unstructured, error) {
var crds []*unstructured.Unstructured
@@ -378,9 +600,9 @@ func readCRDs(basePath string, files []os.FileInfo) ([]*unstructured.Unstructure
return crds, nil
}
// readDocuments reads documents from file
// readDocuments reads documents from file.
func readDocuments(fp string) ([][]byte, error) {
b, err := ioutil.ReadFile(fp)
b, err := ioutil.ReadFile(fp) //nolint:gosec
if err != nil {
return nil, err
}