From 46b995a089aecde9b8661315c67b7516421fe530 Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Sat, 18 Nov 2017 12:05:06 -0800 Subject: [PATCH] Revendor kutil (#230) --- .../typed/stash/v1alpha1/util/kubernetes.go | 6 +- glide.lock | 18 +- pkg/migrator/migrate.go | 4 +- .../kutil/apiextensions/v1beta1/kubernetes.go | 42 + .../appscode/kutil/apps/v1beta1/kubernetes.go | 16 +- .../appscode/kutil/core/v1/kubernetes.go | 40 +- .../kutil/extensions/v1beta1/daemonset.go | 3 +- .../kutil/extensions/v1beta1/kubernetes.go | 22 +- .../appscode/kutil/meta/annotations.go | 57 ++ vendor/github.com/appscode/kutil/meta/lib.go | 127 +++ .../appscode/kutil/rbac/v1beta1/kubernetes.go | 20 +- vendor/github.com/appscode/kutil/util.go | 177 +--- .../cpuguy83/go-md2man/md2man/roff.go | 66 +- vendor/github.com/google/uuid/uuid.go | 7 + .../kubernetes/apimachinery/LICENSE | 202 ++++ .../apimachinery/pkg/conversion/cloner.go | 249 +++++ .../apimachinery/pkg/conversion/converter.go | 898 ++++++++++++++++++ .../apimachinery/pkg/conversion/deep_equal.go | 36 + .../apimachinery/pkg/conversion/doc.go | 24 + .../apimachinery/pkg/conversion/helper.go | 39 + 20 files changed, 1799 insertions(+), 254 deletions(-) create mode 100644 vendor/github.com/appscode/kutil/apiextensions/v1beta1/kubernetes.go create mode 100644 vendor/github.com/appscode/kutil/meta/annotations.go create mode 100644 vendor/github.com/appscode/kutil/meta/lib.go create mode 100644 vendor/github.com/kubernetes/apimachinery/LICENSE create mode 100644 vendor/github.com/kubernetes/apimachinery/pkg/conversion/cloner.go create mode 100644 vendor/github.com/kubernetes/apimachinery/pkg/conversion/converter.go create mode 100644 vendor/github.com/kubernetes/apimachinery/pkg/conversion/deep_equal.go create mode 100644 vendor/github.com/kubernetes/apimachinery/pkg/conversion/doc.go create mode 100644 vendor/github.com/kubernetes/apimachinery/pkg/conversion/helper.go diff --git a/client/typed/stash/v1alpha1/util/kubernetes.go b/client/typed/stash/v1alpha1/util/kubernetes.go index 7987e743e..59d0911ba 100644 --- a/client/typed/stash/v1alpha1/util/kubernetes.go +++ b/client/typed/stash/v1alpha1/util/kubernetes.go @@ -5,13 +5,13 @@ import ( "fmt" "reflect" - "github.com/appscode/kutil" + "github.com/appscode/kutil/meta" api "github.com/appscode/stash/apis/stash/v1alpha1" "k8s.io/apimachinery/pkg/runtime/schema" ) func GetGroupVersionKind(v interface{}) schema.GroupVersionKind { - return api.SchemeGroupVersion.WithKind(kutil.GetKind(v)) + return api.SchemeGroupVersion.WithKind(meta.GetKind(v)) } func AssignTypeKind(v interface{}) error { @@ -22,7 +22,7 @@ func AssignTypeKind(v interface{}) error { switch u := v.(type) { case *api.Restic: u.APIVersion = api.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil } return errors.New("unknown api object type") diff --git a/glide.lock b/glide.lock index 65ad704ae..588084e3a 100644 --- a/glide.lock +++ b/glide.lock @@ -1,8 +1,8 @@ hash: dfae8e6290d081506cc9d8528f165cbfecb4ba40e6f0ddfc6f531ef5a70955cc -updated: 2017-11-11T16:26:15.983444489-08:00 +updated: 2017-11-18T11:29:12.924029859-08:00 imports: - name: github.com/appscode/go - version: 6c0d0eba230ad31f74a18b44beee6f865b01bdec + version: 1cd97c853ad364376f9c792106deb0bfd197bca0 subpackages: - context - crypto/rand @@ -13,11 +13,13 @@ imports: - types - version - name: github.com/appscode/kutil - version: 4b4f67973f42bf9a5355c6b4c2d00040833d4143 + version: c7547d78847930f4b48c4e3b3d6fe1d8b0309bd7 subpackages: + - apiextensions/v1beta1 - apps/v1beta1 - core/v1 - extensions/v1beta1 + - meta - rbac/v1beta1 - name: github.com/appscode/pat version: 48ff78925b7955367d8a048fc2b5cec8efadf8d3 @@ -32,7 +34,7 @@ imports: - name: github.com/codeskyblue/go-sh version: 703901965097a6b3155c0f6f774efb877b483f64 - name: github.com/cpuguy83/go-md2man - version: 71acacd42f85e5e82f70a55327789582a5200a90 + version: 1d903dcb749992f3741d744c0f8376b4bd7eb3e1 subpackages: - md2man - name: github.com/davecgh/go-spew @@ -100,7 +102,7 @@ imports: - name: github.com/google/gofuzz version: 44d81051d367757e1c7c6a5a86423ece9afcf63c - name: github.com/google/uuid - version: e367a344cbe8e08149f9951115dc299ebd42b919 + version: 8c31c18f31ede9fc8eae72290a7e7a8064e9b3e3 - name: github.com/googleapis/gnostic version: 0c5108395e2debce0d731cf0287ddf7242066aba subpackages: @@ -141,6 +143,10 @@ imports: version: 36b14963da70d11297d313183d7e6388c8510e1e - name: github.com/juju/ratelimit version: 5b9ff866471762aa2ab2dced63c9fb6f53921342 +- name: github.com/kubernetes/apimachinery + version: 18a564baac720819100827c16fdebcadb05b2d0d + subpackages: + - pkg/conversion - name: github.com/mailru/easyjson version: d5b7844b561a7bc640052f1b935f7b800330d7e0 subpackages: @@ -222,7 +228,7 @@ imports: - name: github.com/sirupsen/logrus version: f006c2ac4710855cf0f916dd6b77acf6b048dc6e - name: github.com/spf13/cobra - version: 2da4a54c5ceefcee7ca5dd0eea1e18a3b6366489 + version: d6948b782c9f4799ea3cd225f6de4131c29c243a subpackages: - doc - name: github.com/spf13/pflag diff --git a/pkg/migrator/migrate.go b/pkg/migrator/migrate.go index ebc2c9dba..2bbc12f19 100644 --- a/pkg/migrator/migrate.go +++ b/pkg/migrator/migrate.go @@ -6,7 +6,7 @@ import ( "time" "github.com/appscode/go/log" - "github.com/appscode/kutil" + apiext_util "github.com/appscode/kutil/apiextensions/v1beta1" "github.com/appscode/stash/apis/stash" api "github.com/appscode/stash/apis/stash/v1alpha1" "github.com/hashicorp/go-version" @@ -151,7 +151,7 @@ func (m *migrator) createCRDs() error { } } } - return kutil.WaitForCRDReady(m.kubeClient.CoreV1().RESTClient(), crds) + return apiext_util.WaitForCRDReady(m.kubeClient.CoreV1().RESTClient(), crds) } func (m *migrator) rollback() error { diff --git a/vendor/github.com/appscode/kutil/apiextensions/v1beta1/kubernetes.go b/vendor/github.com/appscode/kutil/apiextensions/v1beta1/kubernetes.go new file mode 100644 index 000000000..3bfb146e5 --- /dev/null +++ b/vendor/github.com/appscode/kutil/apiextensions/v1beta1/kubernetes.go @@ -0,0 +1,42 @@ +package v1beta1 + +import ( + "fmt" + "net/http" + "time" + + "github.com/pkg/errors" + apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + kerr "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/rest" +) + +func WaitForCRDReady(restClient rest.Interface, crds []*apiextensions.CustomResourceDefinition) error { + err := wait.Poll(3*time.Second, 5*time.Minute, func() (bool, error) { + for _, crd := range crds { + res := restClient.Get().AbsPath("apis", crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Plural).Do() + err := res.Error() + if err != nil { + // RESTClient returns *apierrors.StatusError for any status codes < 200 or > 206 + // and http.Client.Do errors are returned directly. + if se, ok := err.(*kerr.StatusError); ok { + if se.Status().Code == http.StatusNotFound { + return false, nil + } + } + return false, err + } + + var statusCode int + res.StatusCode(&statusCode) + if statusCode != http.StatusOK { + return false, fmt.Errorf("invalid status code: %d", statusCode) + } + } + + return true, nil + }) + + return errors.Wrap(err, fmt.Sprintf("timed out waiting for CRD")) +} diff --git a/vendor/github.com/appscode/kutil/apps/v1beta1/kubernetes.go b/vendor/github.com/appscode/kutil/apps/v1beta1/kubernetes.go index f71e8a0f3..2b2f3a935 100644 --- a/vendor/github.com/appscode/kutil/apps/v1beta1/kubernetes.go +++ b/vendor/github.com/appscode/kutil/apps/v1beta1/kubernetes.go @@ -2,31 +2,31 @@ package v1beta1 import ( "errors" - "fmt" - "reflect" - "github.com/appscode/kutil" + "github.com/appscode/kutil/meta" + "github.com/kubernetes/apimachinery/pkg/conversion" apps "k8s.io/api/apps/v1beta1" "k8s.io/apimachinery/pkg/runtime/schema" ) func GetGroupVersionKind(v interface{}) schema.GroupVersionKind { - return apps.SchemeGroupVersion.WithKind(kutil.GetKind(v)) + return apps.SchemeGroupVersion.WithKind(meta.GetKind(v)) } func AssignTypeKind(v interface{}) error { - if reflect.ValueOf(v).Kind() != reflect.Ptr { - return fmt.Errorf("%v must be a pointer", v) + _, err := conversion.EnforcePtr(v) + if err != nil { + return err } switch u := v.(type) { case *apps.StatefulSet: u.APIVersion = apps.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *apps.Deployment: u.APIVersion = apps.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil } return errors.New("unknown api object type") diff --git a/vendor/github.com/appscode/kutil/core/v1/kubernetes.go b/vendor/github.com/appscode/kutil/core/v1/kubernetes.go index 4a36fbfc9..425f60378 100644 --- a/vendor/github.com/appscode/kutil/core/v1/kubernetes.go +++ b/vendor/github.com/appscode/kutil/core/v1/kubernetes.go @@ -2,80 +2,80 @@ package v1 import ( "errors" - "fmt" - "reflect" - "github.com/appscode/kutil" + "github.com/appscode/kutil/meta" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/runtime/schema" ) func GetGroupVersionKind(v interface{}) schema.GroupVersionKind { - return core.SchemeGroupVersion.WithKind(kutil.GetKind(v)) + return core.SchemeGroupVersion.WithKind(meta.GetKind(v)) } func AssignTypeKind(v interface{}) error { - if reflect.ValueOf(v).Kind() != reflect.Ptr { - return fmt.Errorf("%v must be a pointer", v) + _, err := conversion.EnforcePtr(v) + if err != nil { + return err } switch u := v.(type) { case *core.Pod: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.ReplicationController: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.ConfigMap: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.Secret: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.Service: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.PersistentVolumeClaim: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.PersistentVolume: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.Node: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.ServiceAccount: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.Namespace: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.Endpoints: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.ComponentStatus: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.LimitRange: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *core.Event: u.APIVersion = core.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil } return errors.New("unknown api object type") diff --git a/vendor/github.com/appscode/kutil/extensions/v1beta1/daemonset.go b/vendor/github.com/appscode/kutil/extensions/v1beta1/daemonset.go index 44ffab466..5cd69700e 100644 --- a/vendor/github.com/appscode/kutil/extensions/v1beta1/daemonset.go +++ b/vendor/github.com/appscode/kutil/extensions/v1beta1/daemonset.go @@ -14,6 +14,7 @@ import ( "k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" + "github.com/appscode/kutil/meta" ) func CreateOrPatchDaemonSet(c kubernetes.Interface, meta metav1.ObjectMeta, transform func(*extensions.DaemonSet) *extensions.DaemonSet) (*extensions.DaemonSet, error) { @@ -53,7 +54,7 @@ func PatchDaemonSet(c kubernetes.Interface, cur *extensions.DaemonSet, transform } glog.V(3).Infof("Patching DaemonSet %s/%s with %s.", cur.Namespace, cur.Name, string(patch)) result, err := c.ExtensionsV1beta1().DaemonSets(cur.Namespace).Patch(cur.Name, types.StrategicMergePatchType, patch) - if ok, err := kutil.CheckAPIVersion(c, "<= 1.5"); err == nil && ok { + if ok, err := meta.CheckAPIVersion(c, "<= 1.5"); err == nil && ok { // https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/ core_util.RestartPods(c, cur.Namespace, cur.Spec.Selector) } diff --git a/vendor/github.com/appscode/kutil/extensions/v1beta1/kubernetes.go b/vendor/github.com/appscode/kutil/extensions/v1beta1/kubernetes.go index 8d8add3c4..afa56fb1b 100644 --- a/vendor/github.com/appscode/kutil/extensions/v1beta1/kubernetes.go +++ b/vendor/github.com/appscode/kutil/extensions/v1beta1/kubernetes.go @@ -2,43 +2,43 @@ package v1beta1 import ( "errors" - "fmt" - "reflect" - "github.com/appscode/kutil" + "github.com/appscode/kutil/meta" + "github.com/kubernetes/apimachinery/pkg/conversion" extensions "k8s.io/api/extensions/v1beta1" "k8s.io/apimachinery/pkg/runtime/schema" ) func GetGroupVersionKind(v interface{}) schema.GroupVersionKind { - return extensions.SchemeGroupVersion.WithKind(kutil.GetKind(v)) + return extensions.SchemeGroupVersion.WithKind(meta.GetKind(v)) } func AssignTypeKind(v interface{}) error { - if reflect.ValueOf(v).Kind() != reflect.Ptr { - return fmt.Errorf("%v must be a pointer", v) + _, err := conversion.EnforcePtr(v) + if err != nil { + return err } switch u := v.(type) { case *extensions.Ingress: u.APIVersion = extensions.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *extensions.DaemonSet: u.APIVersion = extensions.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *extensions.ReplicaSet: u.APIVersion = extensions.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *extensions.Deployment: u.APIVersion = extensions.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *extensions.ThirdPartyResource: u.APIVersion = extensions.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil } return errors.New("unknown api object type") diff --git a/vendor/github.com/appscode/kutil/meta/annotations.go b/vendor/github.com/appscode/kutil/meta/annotations.go new file mode 100644 index 000000000..28bf95d39 --- /dev/null +++ b/vendor/github.com/appscode/kutil/meta/annotations.go @@ -0,0 +1,57 @@ +package meta + +import ( + "encoding/json" + "strconv" +) + +func GetBool(m map[string]string, key string) (bool, error) { + if m == nil { + return false, nil + } + return strconv.ParseBool(m[key]) +} + +func GetInt(m map[string]string, key string) (int, error) { + if m == nil { + return 0, nil + } + s, ok := m[key] + if !ok { + return 0, nil + } + return strconv.Atoi(s) +} + +func GetString(m map[string]string, key string) string { + if m == nil { + return "" + } + return m[key] +} + +func GetList(m map[string]string, key string) ([]string, error) { + if m == nil { + return []string{}, nil + } + s, ok := m[key] + if !ok { + return []string{}, nil + } + v := make([]string, 0) + err := json.Unmarshal([]byte(s), &v) + return v, err +} + +func GetMap(m map[string]string, key string) (map[string]string, error) { + if m == nil { + return map[string]string{}, nil + } + s, ok := m[key] + if !ok { + return map[string]string{}, nil + } + v := make(map[string]string) + err := json.Unmarshal([]byte(s), &v) + return v, err +} diff --git a/vendor/github.com/appscode/kutil/meta/lib.go b/vendor/github.com/appscode/kutil/meta/lib.go new file mode 100644 index 000000000..323a75386 --- /dev/null +++ b/vendor/github.com/appscode/kutil/meta/lib.go @@ -0,0 +1,127 @@ +package meta + +import ( + "fmt" + "io/ioutil" + "os" + "reflect" + "strings" + + "github.com/hashicorp/go-version" + core "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes" + clientsetscheme "k8s.io/client-go/kubernetes/scheme" +) + +func Namespace() string { + if ns := os.Getenv("KUBE_NAMESPACE"); ns != "" { + return ns + } + if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { + if ns := strings.TrimSpace(string(data)); len(ns) > 0 { + return ns + } + } + return core.NamespaceDefault +} + +func IsPreferredAPIResource(c kubernetes.Interface, groupVersion, kind string) bool { + if resourceList, err := c.Discovery().ServerPreferredResources(); err == nil { + for _, resources := range resourceList { + if resources.GroupVersion != groupVersion { + continue + } + for _, resource := range resources.APIResources { + if resources.GroupVersion == groupVersion && resource.Kind == kind { + return true + } + } + } + } + return false +} + +func CheckAPIVersion(c kubernetes.Interface, constraint string) (bool, error) { + info, err := c.Discovery().ServerVersion() + if err != nil { + return false, err + } + cond, err := version.NewConstraint(constraint) + if err != nil { + return false, err + } + v, err := version.NewVersion(info.GitVersion) + if err != nil { + return false, err + } + return cond.Check(v.ToMutator().ResetPrerelease().ResetMetadata().Done()), nil +} + +func DeleteInBackground() *metav1.DeleteOptions { + policy := metav1.DeletePropagationBackground + return &metav1.DeleteOptions{PropagationPolicy: &policy} +} + +func DeleteInForeground() *metav1.DeleteOptions { + policy := metav1.DeletePropagationForeground + return &metav1.DeleteOptions{PropagationPolicy: &policy} +} + +func GetKind(v interface{}) string { + val := reflect.ValueOf(v) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + return val.Type().Name() +} + +// MarshalToYAML marshals an object into yaml. +func MarshalToYAML(obj runtime.Object, gv schema.GroupVersion) ([]byte, error) { + mediaType := "application/yaml" + info, ok := runtime.SerializerInfoForMediaType(clientsetscheme.Codecs.SupportedMediaTypes(), mediaType) + if !ok { + return []byte{}, fmt.Errorf("unsupported media type %q", mediaType) + } + + encoder := clientsetscheme.Codecs.EncoderForVersion(info.Serializer, gv) + return runtime.Encode(encoder, obj) +} + +// UnmarshalToYAML unmarshals an object into yaml. +func UnmarshalToYAML(data []byte, gv schema.GroupVersion) (runtime.Object, error) { + mediaType := "application/yaml" + info, ok := runtime.SerializerInfoForMediaType(clientsetscheme.Codecs.SupportedMediaTypes(), mediaType) + if !ok { + return nil, fmt.Errorf("unsupported media type %q", mediaType) + } + + decoder := clientsetscheme.Codecs.DecoderToVersion(info.Serializer, gv) + return runtime.Decode(decoder, data) +} + +// MarshalToJson marshals an object into json. +func MarshalToJson(obj runtime.Object, gv schema.GroupVersion) ([]byte, error) { + mediaType := "application/json" + info, ok := runtime.SerializerInfoForMediaType(clientsetscheme.Codecs.SupportedMediaTypes(), mediaType) + if !ok { + return []byte{}, fmt.Errorf("unsupported media type %q", mediaType) + } + + encoder := clientsetscheme.Codecs.EncoderForVersion(info.Serializer, gv) + return runtime.Encode(encoder, obj) +} + +// UnmarshalToJSON unmarshals an object into json. +func UnmarshalToJSON(data []byte, gv schema.GroupVersion) (runtime.Object, error) { + mediaType := "application/json" + info, ok := runtime.SerializerInfoForMediaType(clientsetscheme.Codecs.SupportedMediaTypes(), mediaType) + if !ok { + return nil, fmt.Errorf("unsupported media type %q", mediaType) + } + + decoder := clientsetscheme.Codecs.DecoderToVersion(info.Serializer, gv) + return runtime.Decode(decoder, data) +} diff --git a/vendor/github.com/appscode/kutil/rbac/v1beta1/kubernetes.go b/vendor/github.com/appscode/kutil/rbac/v1beta1/kubernetes.go index 284743d4e..9d23c9049 100644 --- a/vendor/github.com/appscode/kutil/rbac/v1beta1/kubernetes.go +++ b/vendor/github.com/appscode/kutil/rbac/v1beta1/kubernetes.go @@ -2,39 +2,39 @@ package v1beta1 import ( "errors" - "fmt" - "reflect" - "github.com/appscode/kutil" + "github.com/appscode/kutil/meta" + "github.com/kubernetes/apimachinery/pkg/conversion" rbac "k8s.io/api/rbac/v1beta1" "k8s.io/apimachinery/pkg/runtime/schema" ) func GetGroupVersionKind(v interface{}) schema.GroupVersionKind { - return rbac.SchemeGroupVersion.WithKind(kutil.GetKind(v)) + return rbac.SchemeGroupVersion.WithKind(meta.GetKind(v)) } func AssignTypeKind(v interface{}) error { - if reflect.ValueOf(v).Kind() != reflect.Ptr { - return fmt.Errorf("%v must be a pointer", v) + _, err := conversion.EnforcePtr(v) + if err != nil { + return err } switch u := v.(type) { case *rbac.Role: u.APIVersion = rbac.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *rbac.RoleBinding: u.APIVersion = rbac.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *rbac.ClusterRole: u.APIVersion = rbac.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil case *rbac.ClusterRoleBinding: u.APIVersion = rbac.SchemeGroupVersion.String() - u.Kind = kutil.GetKind(v) + u.Kind = meta.GetKind(v) return nil } return errors.New("unknown api object type") diff --git a/vendor/github.com/appscode/kutil/util.go b/vendor/github.com/appscode/kutil/util.go index 9ab5428ba..643dd0013 100644 --- a/vendor/github.com/appscode/kutil/util.go +++ b/vendor/github.com/appscode/kutil/util.go @@ -1,183 +1,8 @@ package kutil -import ( - "fmt" - "github.com/hashicorp/go-version" - "github.com/pkg/errors" - "io/ioutil" - core "k8s.io/api/core/v1" - apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - kerr "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" - clientsetscheme "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "net/http" - "os" - "reflect" - "strings" - "time" -) +import "time" const ( RetryInterval = 50 * time.Millisecond RetryTimeout = 2 * time.Second ) - -func Namespace() string { - if ns := os.Getenv("KUBE_NAMESPACE"); ns != "" { - return ns - } - if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { - if ns := strings.TrimSpace(string(data)); len(ns) > 0 { - return ns - } - } - return core.NamespaceDefault -} - -func IsPreferredAPIResource(c kubernetes.Interface, groupVersion, kind string) bool { - if resourceList, err := c.Discovery().ServerPreferredResources(); err == nil { - for _, resources := range resourceList { - if resources.GroupVersion != groupVersion { - continue - } - for _, resource := range resources.APIResources { - if resources.GroupVersion == groupVersion && resource.Kind == kind { - return true - } - } - } - } - return false -} - -func CheckAPIVersion(c kubernetes.Interface, constraint string) (bool, error) { - info, err := c.Discovery().ServerVersion() - if err != nil { - return false, err - } - cond, err := version.NewConstraint(constraint) - if err != nil { - return false, err - } - v, err := version.NewVersion(info.GitVersion) - if err != nil { - return false, err - } - return cond.Check(v.ToMutator().ResetPrerelease().ResetMetadata().Done()), nil -} - -func WaitForCRDReady(restClient rest.Interface, crds []*apiextensions.CustomResourceDefinition) error { - err := wait.Poll(3*time.Second, 5*time.Minute, func() (bool, error) { - for _, crd := range crds { - res := restClient.Get().AbsPath("apis", crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Plural).Do() - err := res.Error() - if err != nil { - // RESTClient returns *apierrors.StatusError for any status codes < 200 or > 206 - // and http.Client.Do errors are returned directly. - if se, ok := err.(*kerr.StatusError); ok { - if se.Status().Code == http.StatusNotFound { - return false, nil - } - } - return false, err - } - - var statusCode int - res.StatusCode(&statusCode) - if statusCode != http.StatusOK { - return false, fmt.Errorf("invalid status code: %d", statusCode) - } - } - - return true, nil - }) - - return errors.Wrap(err, fmt.Sprintf("timed out waiting for CRD")) -} - -func DeleteInBackground() *metav1.DeleteOptions { - policy := metav1.DeletePropagationBackground - return &metav1.DeleteOptions{PropagationPolicy: &policy} -} - -func DeleteInForeground() *metav1.DeleteOptions { - policy := metav1.DeletePropagationForeground - return &metav1.DeleteOptions{PropagationPolicy: &policy} -} - -func GetKind(v interface{}) string { - val := reflect.ValueOf(v) - if val.Kind() == reflect.Ptr { - val = val.Elem() - } - return val.Type().Name() -} - -func GetObjectReference(v interface{}, gv schema.GroupVersion) *core.ObjectReference { - m, err := meta.Accessor(v) - if err != nil { - return &core.ObjectReference{} - } - return &core.ObjectReference{ - APIVersion: gv.String(), - Kind: GetKind(v), - Namespace: m.GetNamespace(), - Name: m.GetName(), - UID: m.GetUID(), - ResourceVersion: m.GetResourceVersion(), - } -} - -// MarshalToYAML marshals an object into yaml. -func MarshalToYAML(obj runtime.Object, gv schema.GroupVersion) ([]byte, error) { - mediaType := "application/yaml" - info, ok := runtime.SerializerInfoForMediaType(clientsetscheme.Codecs.SupportedMediaTypes(), mediaType) - if !ok { - return []byte{}, fmt.Errorf("unsupported media type %q", mediaType) - } - - encoder := clientsetscheme.Codecs.EncoderForVersion(info.Serializer, gv) - return runtime.Encode(encoder, obj) -} - -// UnmarshalToYAML unmarshals an object into yaml. -func UnmarshalToYAML(data []byte, gv schema.GroupVersion) (runtime.Object, error) { - mediaType := "application/yaml" - info, ok := runtime.SerializerInfoForMediaType(clientsetscheme.Codecs.SupportedMediaTypes(), mediaType) - if !ok { - return nil, fmt.Errorf("unsupported media type %q", mediaType) - } - - decoder := clientsetscheme.Codecs.DecoderToVersion(info.Serializer, gv) - return runtime.Decode(decoder, data) -} - -// MarshalToJson marshals an object into json. -func MarshalToJson(obj runtime.Object, gv schema.GroupVersion) ([]byte, error) { - mediaType := "application/json" - info, ok := runtime.SerializerInfoForMediaType(clientsetscheme.Codecs.SupportedMediaTypes(), mediaType) - if !ok { - return []byte{}, fmt.Errorf("unsupported media type %q", mediaType) - } - - encoder := clientsetscheme.Codecs.EncoderForVersion(info.Serializer, gv) - return runtime.Encode(encoder, obj) -} - -// UnmarshalToJSON unmarshals an object into json. -func UnmarshalToJSON(data []byte, gv schema.GroupVersion) (runtime.Object, error) { - mediaType := "application/json" - info, ok := runtime.SerializerInfoForMediaType(clientsetscheme.Codecs.SupportedMediaTypes(), mediaType) - if !ok { - return nil, fmt.Errorf("unsupported media type %q", mediaType) - } - - decoder := clientsetscheme.Codecs.DecoderToVersion(info.Serializer, gv) - return runtime.Decode(decoder, data) -} diff --git a/vendor/github.com/cpuguy83/go-md2man/md2man/roff.go b/vendor/github.com/cpuguy83/go-md2man/md2man/roff.go index 4478786b7..292fca343 100644 --- a/vendor/github.com/cpuguy83/go-md2man/md2man/roff.go +++ b/vendor/github.com/cpuguy83/go-md2man/md2man/roff.go @@ -11,6 +11,8 @@ import ( type roffRenderer struct{} +var listCounter int + func RoffRenderer(flags int) blackfriday.Renderer { return &roffRenderer{} } @@ -33,8 +35,12 @@ func (r *roffRenderer) TitleBlock(out *bytes.Buffer, text []byte) { line = append(line, []byte("\" ")...) out.Write(line) } + out.WriteString("\n") - out.WriteString(" \"\"\n") + // disable hyphenation + out.WriteString(".nh\n") + // disable justification (adjust text to left margin only) + out.WriteString(".ad l\n") } func (r *roffRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string) { @@ -80,23 +86,24 @@ func (r *roffRenderer) HRule(out *bytes.Buffer) { func (r *roffRenderer) List(out *bytes.Buffer, text func() bool, flags int) { marker := out.Len() - out.WriteString(".IP ") if flags&blackfriday.LIST_TYPE_ORDERED != 0 { - out.WriteString("\\(bu 2") - } else { - out.WriteString("\\n+[step" + string(flags) + "]") + listCounter = 1 } - out.WriteString("\n") if !text() { out.Truncate(marker) return } - } func (r *roffRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) { - out.WriteString("\n\\item ") + if flags&blackfriday.LIST_TYPE_ORDERED != 0 { + out.WriteString(fmt.Sprintf(".IP \"%3d.\" 5\n", listCounter)) + listCounter += 1 + } else { + out.WriteString(".IP \\(bu 2\n") + } out.Write(text) + out.WriteString("\n") } func (r *roffRenderer) Paragraph(out *bytes.Buffer, text func() bool) { @@ -111,11 +118,24 @@ func (r *roffRenderer) Paragraph(out *bytes.Buffer, text func() bool) { } } -// TODO: This might now work func (r *roffRenderer) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) { - out.WriteString(".TS\nallbox;\n") - + out.WriteString("\n.TS\nallbox;\n") + + max_delims := 0 + lines := strings.Split(strings.TrimRight(string(header), "\n")+"\n"+strings.TrimRight(string(body), "\n"), "\n") + for _, w := range lines { + cur_delims := strings.Count(w, "\t") + if cur_delims > max_delims { + max_delims = cur_delims + } + } + out.Write([]byte(strings.Repeat("l ", max_delims+1) + "\n")) + out.Write([]byte(strings.Repeat("l ", max_delims+1) + ".\n")) out.Write(header) + if len(header) > 0 { + out.Write([]byte("\n")) + } + out.Write(body) out.WriteString("\n.TE\n") } @@ -125,24 +145,30 @@ func (r *roffRenderer) TableRow(out *bytes.Buffer, text []byte) { out.WriteString("\n") } out.Write(text) - out.WriteString("\n") } func (r *roffRenderer) TableHeaderCell(out *bytes.Buffer, text []byte, align int) { if out.Len() > 0 { - out.WriteString(" ") + out.WriteString("\t") } - out.Write(text) - out.WriteString(" ") + if len(text) == 0 { + text = []byte{' '} + } + out.Write([]byte("\\fB\\fC" + string(text) + "\\fR")) } -// TODO: This is probably broken func (r *roffRenderer) TableCell(out *bytes.Buffer, text []byte, align int) { if out.Len() > 0 { out.WriteString("\t") } + if len(text) > 30 { + text = append([]byte("T{\n"), text...) + text = append(text, []byte("\nT}")...) + } + if len(text) == 0 { + text = []byte{' '} + } out.Write(text) - out.WriteString("\t") } func (r *roffRenderer) Footnotes(out *bytes.Buffer, text func() bool) { @@ -185,6 +211,7 @@ func (r *roffRenderer) LineBreak(out *bytes.Buffer) { } func (r *roffRenderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { + out.Write(content) r.AutoLink(out, link, 0) } @@ -249,6 +276,11 @@ func needsBackslash(c byte) bool { func escapeSpecialChars(out *bytes.Buffer, text []byte) { for i := 0; i < len(text); i++ { + // escape initial apostrophe or period + if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') { + out.WriteString("\\&") + } + // directly copy normal characters org := i diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go index 23161a86c..1320d60d8 100644 --- a/vendor/github.com/google/uuid/uuid.go +++ b/vendor/github.com/google/uuid/uuid.go @@ -97,6 +97,13 @@ func ParseBytes(b []byte) (UUID, error) { return uuid, nil } +// FromBytes creates a new UUID from a byte slice. Returns an error if the slice +// does not have a length of 16. The bytes are copied from the slice. +func FromBytes(b []byte) (uuid UUID, err error) { + err = uuid.UnmarshalBinary(b) + return uuid, err +} + // Must returns uuid if err is nil and panics otherwise. func Must(uuid UUID, err error) UUID { if err != nil { diff --git a/vendor/github.com/kubernetes/apimachinery/LICENSE b/vendor/github.com/kubernetes/apimachinery/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/kubernetes/apimachinery/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/github.com/kubernetes/apimachinery/pkg/conversion/cloner.go b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/cloner.go new file mode 100644 index 000000000..c5dec1f31 --- /dev/null +++ b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/cloner.go @@ -0,0 +1,249 @@ +/* +Copyright 2014 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 conversion + +import ( + "fmt" + "reflect" +) + +// Cloner knows how to copy one type to another. +type Cloner struct { + // Map from the type to a function which can do the deep copy. + deepCopyFuncs map[reflect.Type]reflect.Value + generatedDeepCopyFuncs map[reflect.Type]func(in interface{}, out interface{}, c *Cloner) error +} + +// NewCloner creates a new Cloner object. +func NewCloner() *Cloner { + c := &Cloner{ + deepCopyFuncs: map[reflect.Type]reflect.Value{}, + generatedDeepCopyFuncs: map[reflect.Type]func(in interface{}, out interface{}, c *Cloner) error{}, + } + if err := c.RegisterDeepCopyFunc(byteSliceDeepCopy); err != nil { + // If one of the deep-copy functions is malformed, detect it immediately. + panic(err) + } + return c +} + +// Prevent recursing into every byte... +func byteSliceDeepCopy(in *[]byte, out *[]byte, c *Cloner) error { + if *in != nil { + *out = make([]byte, len(*in)) + copy(*out, *in) + } else { + *out = nil + } + return nil +} + +// Verifies whether a deep-copy function has a correct signature. +func verifyDeepCopyFunctionSignature(ft reflect.Type) error { + if ft.Kind() != reflect.Func { + return fmt.Errorf("expected func, got: %v", ft) + } + if ft.NumIn() != 3 { + return fmt.Errorf("expected three 'in' params, got %v", ft) + } + if ft.NumOut() != 1 { + return fmt.Errorf("expected one 'out' param, got %v", ft) + } + if ft.In(0).Kind() != reflect.Ptr { + return fmt.Errorf("expected pointer arg for 'in' param 0, got: %v", ft) + } + if ft.In(1) != ft.In(0) { + return fmt.Errorf("expected 'in' param 0 the same as param 1, got: %v", ft) + } + var forClonerType Cloner + if expected := reflect.TypeOf(&forClonerType); ft.In(2) != expected { + return fmt.Errorf("expected '%v' arg for 'in' param 2, got: '%v'", expected, ft.In(2)) + } + var forErrorType error + // This convolution is necessary, otherwise TypeOf picks up on the fact + // that forErrorType is nil + errorType := reflect.TypeOf(&forErrorType).Elem() + if ft.Out(0) != errorType { + return fmt.Errorf("expected error return, got: %v", ft) + } + return nil +} + +// RegisterGeneratedDeepCopyFunc registers a copying func with the Cloner. +// deepCopyFunc must take three parameters: a type input, a pointer to a +// type output, and a pointer to Cloner. It should return an error. +// +// Example: +// c.RegisterGeneratedDeepCopyFunc( +// func(in Pod, out *Pod, c *Cloner) error { +// // deep copy logic... +// return nil +// }) +func (c *Cloner) RegisterDeepCopyFunc(deepCopyFunc interface{}) error { + fv := reflect.ValueOf(deepCopyFunc) + ft := fv.Type() + if err := verifyDeepCopyFunctionSignature(ft); err != nil { + return err + } + c.deepCopyFuncs[ft.In(0)] = fv + return nil +} + +// GeneratedDeepCopyFunc bundles an untyped generated deep-copy function of a type +// with a reflection type object used as a key to lookup the deep-copy function. +type GeneratedDeepCopyFunc struct { + Fn func(in interface{}, out interface{}, c *Cloner) error + InType reflect.Type +} + +// Similar to RegisterDeepCopyFunc, but registers deep copy function that were +// automatically generated. +func (c *Cloner) RegisterGeneratedDeepCopyFunc(fn GeneratedDeepCopyFunc) error { + c.generatedDeepCopyFuncs[fn.InType] = fn.Fn + return nil +} + +// DeepCopy will perform a deep copy of a given object. +func (c *Cloner) DeepCopy(in interface{}) (interface{}, error) { + // Can be invalid if we run DeepCopy(X) where X is a nil interface type. + // For example, we get an invalid value when someone tries to deep-copy + // a nil labels.Selector. + // This does not occur if X is nil and is a pointer to a concrete type. + if in == nil { + return nil, nil + } + inValue := reflect.ValueOf(in) + outValue, err := c.deepCopy(inValue) + if err != nil { + return nil, err + } + return outValue.Interface(), nil +} + +func (c *Cloner) deepCopy(src reflect.Value) (reflect.Value, error) { + inType := src.Type() + + switch src.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + if src.IsNil() { + return src, nil + } + } + + if fv, ok := c.deepCopyFuncs[inType]; ok { + return c.customDeepCopy(src, fv) + } + if fv, ok := c.generatedDeepCopyFuncs[inType]; ok { + var outValue reflect.Value + outValue = reflect.New(inType.Elem()) + err := fv(src.Interface(), outValue.Interface(), c) + return outValue, err + } + return c.defaultDeepCopy(src) +} + +func (c *Cloner) customDeepCopy(src, fv reflect.Value) (reflect.Value, error) { + outValue := reflect.New(src.Type().Elem()) + args := []reflect.Value{src, outValue, reflect.ValueOf(c)} + result := fv.Call(args)[0].Interface() + // This convolution is necessary because nil interfaces won't convert + // to error. + if result == nil { + return outValue, nil + } + return outValue, result.(error) +} + +func (c *Cloner) defaultDeepCopy(src reflect.Value) (reflect.Value, error) { + switch src.Kind() { + case reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Uintptr: + return src, fmt.Errorf("cannot deep copy kind: %s", src.Kind()) + case reflect.Array: + dst := reflect.New(src.Type()) + for i := 0; i < src.Len(); i++ { + copyVal, err := c.deepCopy(src.Index(i)) + if err != nil { + return src, err + } + dst.Elem().Index(i).Set(copyVal) + } + return dst.Elem(), nil + case reflect.Interface: + if src.IsNil() { + return src, nil + } + return c.deepCopy(src.Elem()) + case reflect.Map: + if src.IsNil() { + return src, nil + } + dst := reflect.MakeMap(src.Type()) + for _, k := range src.MapKeys() { + copyVal, err := c.deepCopy(src.MapIndex(k)) + if err != nil { + return src, err + } + dst.SetMapIndex(k, copyVal) + } + return dst, nil + case reflect.Ptr: + if src.IsNil() { + return src, nil + } + dst := reflect.New(src.Type().Elem()) + copyVal, err := c.deepCopy(src.Elem()) + if err != nil { + return src, err + } + dst.Elem().Set(copyVal) + return dst, nil + case reflect.Slice: + if src.IsNil() { + return src, nil + } + dst := reflect.MakeSlice(src.Type(), 0, src.Len()) + for i := 0; i < src.Len(); i++ { + copyVal, err := c.deepCopy(src.Index(i)) + if err != nil { + return src, err + } + dst = reflect.Append(dst, copyVal) + } + return dst, nil + case reflect.Struct: + dst := reflect.New(src.Type()) + for i := 0; i < src.NumField(); i++ { + if !dst.Elem().Field(i).CanSet() { + // Can't set private fields. At this point, the + // best we can do is a shallow copy. For + // example, time.Time is a value type with + // private members that can be shallow copied. + return src, nil + } + copyVal, err := c.deepCopy(src.Field(i)) + if err != nil { + return src, err + } + dst.Elem().Field(i).Set(copyVal) + } + return dst.Elem(), nil + + default: + // Value types like numbers, booleans, and strings. + return src, nil + } +} diff --git a/vendor/github.com/kubernetes/apimachinery/pkg/conversion/converter.go b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/converter.go new file mode 100644 index 000000000..7854c207c --- /dev/null +++ b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/converter.go @@ -0,0 +1,898 @@ +/* +Copyright 2014 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 conversion + +import ( + "fmt" + "reflect" +) + +type typePair struct { + source reflect.Type + dest reflect.Type +} + +type typeNamePair struct { + fieldType reflect.Type + fieldName string +} + +// DebugLogger allows you to get debugging messages if necessary. +type DebugLogger interface { + Logf(format string, args ...interface{}) +} + +type NameFunc func(t reflect.Type) string + +var DefaultNameFunc = func(t reflect.Type) string { return t.Name() } + +type GenericConversionFunc func(a, b interface{}, scope Scope) (bool, error) + +// Converter knows how to convert one type to another. +type Converter struct { + // Map from the conversion pair to a function which can + // do the conversion. + conversionFuncs ConversionFuncs + generatedConversionFuncs ConversionFuncs + + // genericConversions are called during normal conversion to offer a "fast-path" + // that avoids all reflection. These methods are not called outside of the .Convert() + // method. + genericConversions []GenericConversionFunc + + // Set of conversions that should be treated as a no-op + ignoredConversions map[typePair]struct{} + + // This is a map from a source field type and name, to a list of destination + // field type and name. + structFieldDests map[typeNamePair][]typeNamePair + + // Allows for the opposite lookup of structFieldDests. So that SourceFromDest + // copy flag also works. So this is a map of destination field name, to potential + // source field name and type to look for. + structFieldSources map[typeNamePair][]typeNamePair + + // Map from an input type to a function which can apply a key name mapping + inputFieldMappingFuncs map[reflect.Type]FieldMappingFunc + + // Map from an input type to a set of default conversion flags. + inputDefaultFlags map[reflect.Type]FieldMatchingFlags + + // If non-nil, will be called to print helpful debugging info. Quite verbose. + Debug DebugLogger + + // nameFunc is called to retrieve the name of a type; this name is used for the + // purpose of deciding whether two types match or not (i.e., will we attempt to + // do a conversion). The default returns the go type name. + nameFunc func(t reflect.Type) string +} + +// NewConverter creates a new Converter object. +func NewConverter(nameFn NameFunc) *Converter { + c := &Converter{ + conversionFuncs: NewConversionFuncs(), + generatedConversionFuncs: NewConversionFuncs(), + ignoredConversions: make(map[typePair]struct{}), + nameFunc: nameFn, + structFieldDests: make(map[typeNamePair][]typeNamePair), + structFieldSources: make(map[typeNamePair][]typeNamePair), + + inputFieldMappingFuncs: make(map[reflect.Type]FieldMappingFunc), + inputDefaultFlags: make(map[reflect.Type]FieldMatchingFlags), + } + c.RegisterConversionFunc(Convert_Slice_byte_To_Slice_byte) + return c +} + +// AddGenericConversionFunc adds a function that accepts the ConversionFunc call pattern +// (for two conversion types) to the converter. These functions are checked first during +// a normal conversion, but are otherwise not called. Use AddConversionFuncs when registering +// typed conversions. +func (c *Converter) AddGenericConversionFunc(fn GenericConversionFunc) { + c.genericConversions = append(c.genericConversions, fn) +} + +// WithConversions returns a Converter that is a copy of c but with the additional +// fns merged on top. +func (c *Converter) WithConversions(fns ConversionFuncs) *Converter { + copied := *c + copied.conversionFuncs = c.conversionFuncs.Merge(fns) + return &copied +} + +// DefaultMeta returns the conversion FieldMappingFunc and meta for a given type. +func (c *Converter) DefaultMeta(t reflect.Type) (FieldMatchingFlags, *Meta) { + return c.inputDefaultFlags[t], &Meta{ + KeyNameMapping: c.inputFieldMappingFuncs[t], + } +} + +// Convert_Slice_byte_To_Slice_byte prevents recursing into every byte +func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error { + if *in == nil { + *out = nil + return nil + } + *out = make([]byte, len(*in)) + copy(*out, *in) + return nil +} + +// Scope is passed to conversion funcs to allow them to continue an ongoing conversion. +// If multiple converters exist in the system, Scope will allow you to use the correct one +// from a conversion function--that is, the one your conversion function was called by. +type Scope interface { + // Call Convert to convert sub-objects. Note that if you call it with your own exact + // parameters, you'll run out of stack space before anything useful happens. + Convert(src, dest interface{}, flags FieldMatchingFlags) error + + // DefaultConvert performs the default conversion, without calling a conversion func + // on the current stack frame. This makes it safe to call from a conversion func. + DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error + + // SrcTags and DestTags contain the struct tags that src and dest had, respectively. + // If the enclosing object was not a struct, then these will contain no tags, of course. + SrcTag() reflect.StructTag + DestTag() reflect.StructTag + + // Flags returns the flags with which the conversion was started. + Flags() FieldMatchingFlags + + // Meta returns any information originally passed to Convert. + Meta() *Meta +} + +// FieldMappingFunc can convert an input field value into different values, depending on +// the value of the source or destination struct tags. +type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string) + +func NewConversionFuncs() ConversionFuncs { + return ConversionFuncs{fns: make(map[typePair]reflect.Value)} +} + +type ConversionFuncs struct { + fns map[typePair]reflect.Value +} + +// Add adds the provided conversion functions to the lookup table - they must have the signature +// `func(type1, type2, Scope) error`. Functions are added in the order passed and will override +// previously registered pairs. +func (c ConversionFuncs) Add(fns ...interface{}) error { + for _, fn := range fns { + fv := reflect.ValueOf(fn) + ft := fv.Type() + if err := verifyConversionFunctionSignature(ft); err != nil { + return err + } + c.fns[typePair{ft.In(0).Elem(), ft.In(1).Elem()}] = fv + } + return nil +} + +// Merge returns a new ConversionFuncs that contains all conversions from +// both other and c, with other conversions taking precedence. +func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs { + merged := NewConversionFuncs() + for k, v := range c.fns { + merged.fns[k] = v + } + for k, v := range other.fns { + merged.fns[k] = v + } + return merged +} + +// Meta is supplied by Scheme, when it calls Convert. +type Meta struct { + // KeyNameMapping is an optional function which may map the listed key (field name) + // into a source and destination value. + KeyNameMapping FieldMappingFunc + // Context is an optional field that callers may use to pass info to conversion functions. + Context interface{} +} + +// scope contains information about an ongoing conversion. +type scope struct { + converter *Converter + meta *Meta + flags FieldMatchingFlags + + // srcStack & destStack are separate because they may not have a 1:1 + // relationship. + srcStack scopeStack + destStack scopeStack +} + +type scopeStackElem struct { + tag reflect.StructTag + value reflect.Value + key string +} + +type scopeStack []scopeStackElem + +func (s *scopeStack) pop() { + n := len(*s) + *s = (*s)[:n-1] +} + +func (s *scopeStack) push(e scopeStackElem) { + *s = append(*s, e) +} + +func (s *scopeStack) top() *scopeStackElem { + return &(*s)[len(*s)-1] +} + +func (s scopeStack) describe() string { + desc := "" + if len(s) > 1 { + desc = "(" + s[1].value.Type().String() + ")" + } + for i, v := range s { + if i < 2 { + // First layer on stack is not real; second is handled specially above. + continue + } + if v.key == "" { + desc += fmt.Sprintf(".%v", v.value.Type()) + } else { + desc += fmt.Sprintf(".%v", v.key) + } + } + return desc +} + +// Formats src & dest as indices for printing. +func (s *scope) setIndices(src, dest int) { + s.srcStack.top().key = fmt.Sprintf("[%v]", src) + s.destStack.top().key = fmt.Sprintf("[%v]", dest) +} + +// Formats src & dest as map keys for printing. +func (s *scope) setKeys(src, dest interface{}) { + s.srcStack.top().key = fmt.Sprintf(`["%v"]`, src) + s.destStack.top().key = fmt.Sprintf(`["%v"]`, dest) +} + +// Convert continues a conversion. +func (s *scope) Convert(src, dest interface{}, flags FieldMatchingFlags) error { + return s.converter.Convert(src, dest, flags, s.meta) +} + +// DefaultConvert continues a conversion, performing a default conversion (no conversion func) +// for the current stack frame. +func (s *scope) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error { + return s.converter.DefaultConvert(src, dest, flags, s.meta) +} + +// SrcTag returns the tag of the struct containing the current source item, if any. +func (s *scope) SrcTag() reflect.StructTag { + return s.srcStack.top().tag +} + +// DestTag returns the tag of the struct containing the current dest item, if any. +func (s *scope) DestTag() reflect.StructTag { + return s.destStack.top().tag +} + +// Flags returns the flags with which the current conversion was started. +func (s *scope) Flags() FieldMatchingFlags { + return s.flags +} + +// Meta returns the meta object that was originally passed to Convert. +func (s *scope) Meta() *Meta { + return s.meta +} + +// describe prints the path to get to the current (source, dest) values. +func (s *scope) describe() (src, dest string) { + return s.srcStack.describe(), s.destStack.describe() +} + +// error makes an error that includes information about where we were in the objects +// we were asked to convert. +func (s *scope) errorf(message string, args ...interface{}) error { + srcPath, destPath := s.describe() + where := fmt.Sprintf("converting %v to %v: ", srcPath, destPath) + return fmt.Errorf(where+message, args...) +} + +// Verifies whether a conversion function has a correct signature. +func verifyConversionFunctionSignature(ft reflect.Type) error { + if ft.Kind() != reflect.Func { + return fmt.Errorf("expected func, got: %v", ft) + } + if ft.NumIn() != 3 { + return fmt.Errorf("expected three 'in' params, got: %v", ft) + } + if ft.NumOut() != 1 { + return fmt.Errorf("expected one 'out' param, got: %v", ft) + } + if ft.In(0).Kind() != reflect.Ptr { + return fmt.Errorf("expected pointer arg for 'in' param 0, got: %v", ft) + } + if ft.In(1).Kind() != reflect.Ptr { + return fmt.Errorf("expected pointer arg for 'in' param 1, got: %v", ft) + } + scopeType := Scope(nil) + if e, a := reflect.TypeOf(&scopeType).Elem(), ft.In(2); e != a { + return fmt.Errorf("expected '%v' arg for 'in' param 2, got '%v' (%v)", e, a, ft) + } + var forErrorType error + // This convolution is necessary, otherwise TypeOf picks up on the fact + // that forErrorType is nil. + errorType := reflect.TypeOf(&forErrorType).Elem() + if ft.Out(0) != errorType { + return fmt.Errorf("expected error return, got: %v", ft) + } + return nil +} + +// RegisterConversionFunc registers a conversion func with the +// Converter. conversionFunc must take three parameters: a pointer to the input +// type, a pointer to the output type, and a conversion.Scope (which should be +// used if recursive conversion calls are desired). It must return an error. +// +// Example: +// c.RegisterConversionFunc( +// func(in *Pod, out *v1.Pod, s Scope) error { +// // conversion logic... +// return nil +// }) +func (c *Converter) RegisterConversionFunc(conversionFunc interface{}) error { + return c.conversionFuncs.Add(conversionFunc) +} + +// Similar to RegisterConversionFunc, but registers conversion function that were +// automatically generated. +func (c *Converter) RegisterGeneratedConversionFunc(conversionFunc interface{}) error { + return c.generatedConversionFuncs.Add(conversionFunc) +} + +// RegisterIgnoredConversion registers a "no-op" for conversion, where any requested +// conversion between from and to is ignored. +func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error { + typeFrom := reflect.TypeOf(from) + typeTo := reflect.TypeOf(to) + if reflect.TypeOf(from).Kind() != reflect.Ptr { + return fmt.Errorf("expected pointer arg for 'from' param 0, got: %v", typeFrom) + } + if typeTo.Kind() != reflect.Ptr { + return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo) + } + c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{} + return nil +} + +// IsConversionIgnored returns true if the specified objects should be dropped during +// conversion. +func (c *Converter) IsConversionIgnored(inType, outType reflect.Type) bool { + _, found := c.ignoredConversions[typePair{inType, outType}] + return found +} + +func (c *Converter) HasConversionFunc(inType, outType reflect.Type) bool { + _, found := c.conversionFuncs.fns[typePair{inType, outType}] + return found +} + +func (c *Converter) ConversionFuncValue(inType, outType reflect.Type) (reflect.Value, bool) { + value, found := c.conversionFuncs.fns[typePair{inType, outType}] + return value, found +} + +// SetStructFieldCopy registers a correspondence. Whenever a struct field is encountered +// which has a type and name matching srcFieldType and srcFieldName, it wil be copied +// into the field in the destination struct matching destFieldType & Name, if such a +// field exists. +// May be called multiple times, even for the same source field & type--all applicable +// copies will be performed. +func (c *Converter) SetStructFieldCopy(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error { + st := reflect.TypeOf(srcFieldType) + dt := reflect.TypeOf(destFieldType) + srcKey := typeNamePair{st, srcFieldName} + destKey := typeNamePair{dt, destFieldName} + c.structFieldDests[srcKey] = append(c.structFieldDests[srcKey], destKey) + c.structFieldSources[destKey] = append(c.structFieldSources[destKey], srcKey) + return nil +} + +// RegisterInputDefaults registers a field name mapping function, used when converting +// from maps to structs. Inputs to the conversion methods are checked for this type and a mapping +// applied automatically if the input matches in. A set of default flags for the input conversion +// may also be provided, which will be used when no explicit flags are requested. +func (c *Converter) RegisterInputDefaults(in interface{}, fn FieldMappingFunc, defaultFlags FieldMatchingFlags) error { + fv := reflect.ValueOf(in) + ft := fv.Type() + if ft.Kind() != reflect.Ptr { + return fmt.Errorf("expected pointer 'in' argument, got: %v", ft) + } + c.inputFieldMappingFuncs[ft] = fn + c.inputDefaultFlags[ft] = defaultFlags + return nil +} + +// FieldMatchingFlags contains a list of ways in which struct fields could be +// copied. These constants may be | combined. +type FieldMatchingFlags int + +const ( + // Loop through destination fields, search for matching source + // field to copy it from. Source fields with no corresponding + // destination field will be ignored. If SourceToDest is + // specified, this flag is ignored. If neither is specified, + // or no flags are passed, this flag is the default. + DestFromSource FieldMatchingFlags = 0 + // Loop through source fields, search for matching dest field + // to copy it into. Destination fields with no corresponding + // source field will be ignored. + SourceToDest FieldMatchingFlags = 1 << iota + // Don't treat it as an error if the corresponding source or + // dest field can't be found. + IgnoreMissingFields + // Don't require type names to match. + AllowDifferentFieldTypeNames +) + +// IsSet returns true if the given flag or combination of flags is set. +func (f FieldMatchingFlags) IsSet(flag FieldMatchingFlags) bool { + if flag == DestFromSource { + // The bit logic doesn't work on the default value. + return f&SourceToDest != SourceToDest + } + return f&flag == flag +} + +// Convert will translate src to dest if it knows how. Both must be pointers. +// If no conversion func is registered and the default copying mechanism +// doesn't work on this type pair, an error will be returned. +// Read the comments on the various FieldMatchingFlags constants to understand +// what the 'flags' parameter does. +// 'meta' is given to allow you to pass information to conversion functions, +// it is not used by Convert() other than storing it in the scope. +// Not safe for objects with cyclic references! +func (c *Converter) Convert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error { + if len(c.genericConversions) > 0 { + // TODO: avoid scope allocation + s := &scope{converter: c, flags: flags, meta: meta} + for _, fn := range c.genericConversions { + if ok, err := fn(src, dest, s); ok { + return err + } + } + } + return c.doConversion(src, dest, flags, meta, c.convert) +} + +// DefaultConvert will translate src to dest if it knows how. Both must be pointers. +// No conversion func is used. If the default copying mechanism +// doesn't work on this type pair, an error will be returned. +// Read the comments on the various FieldMatchingFlags constants to understand +// what the 'flags' parameter does. +// 'meta' is given to allow you to pass information to conversion functions, +// it is not used by DefaultConvert() other than storing it in the scope. +// Not safe for objects with cyclic references! +func (c *Converter) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error { + return c.doConversion(src, dest, flags, meta, c.defaultConvert) +} + +type conversionFunc func(sv, dv reflect.Value, scope *scope) error + +func (c *Converter) doConversion(src, dest interface{}, flags FieldMatchingFlags, meta *Meta, f conversionFunc) error { + dv, err := EnforcePtr(dest) + if err != nil { + return err + } + if !dv.CanAddr() && !dv.CanSet() { + return fmt.Errorf("can't write to dest") + } + sv, err := EnforcePtr(src) + if err != nil { + return err + } + s := &scope{ + converter: c, + flags: flags, + meta: meta, + } + // Leave something on the stack, so that calls to struct tag getters never fail. + s.srcStack.push(scopeStackElem{}) + s.destStack.push(scopeStackElem{}) + return f(sv, dv, s) +} + +// callCustom calls 'custom' with sv & dv. custom must be a conversion function. +func (c *Converter) callCustom(sv, dv, custom reflect.Value, scope *scope) error { + if !sv.CanAddr() { + sv2 := reflect.New(sv.Type()) + sv2.Elem().Set(sv) + sv = sv2 + } else { + sv = sv.Addr() + } + if !dv.CanAddr() { + if !dv.CanSet() { + return scope.errorf("can't addr or set dest.") + } + dvOrig := dv + dv := reflect.New(dvOrig.Type()) + defer func() { dvOrig.Set(dv) }() + } else { + dv = dv.Addr() + } + args := []reflect.Value{sv, dv, reflect.ValueOf(scope)} + ret := custom.Call(args)[0].Interface() + // This convolution is necessary because nil interfaces won't convert + // to errors. + if ret == nil { + return nil + } + return ret.(error) +} + +// convert recursively copies sv into dv, calling an appropriate conversion function if +// one is registered. +func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error { + dt, st := dv.Type(), sv.Type() + pair := typePair{st, dt} + + // ignore conversions of this type + if _, ok := c.ignoredConversions[pair]; ok { + if c.Debug != nil { + c.Debug.Logf("Ignoring conversion of '%v' to '%v'", st, dt) + } + return nil + } + + // Convert sv to dv. + if fv, ok := c.conversionFuncs.fns[pair]; ok { + if c.Debug != nil { + c.Debug.Logf("Calling custom conversion of '%v' to '%v'", st, dt) + } + return c.callCustom(sv, dv, fv, scope) + } + if fv, ok := c.generatedConversionFuncs.fns[pair]; ok { + if c.Debug != nil { + c.Debug.Logf("Calling generated conversion of '%v' to '%v'", st, dt) + } + return c.callCustom(sv, dv, fv, scope) + } + + return c.defaultConvert(sv, dv, scope) +} + +// defaultConvert recursively copies sv into dv. no conversion function is called +// for the current stack frame (but conversion functions may be called for nested objects) +func (c *Converter) defaultConvert(sv, dv reflect.Value, scope *scope) error { + dt, st := dv.Type(), sv.Type() + + if !dv.CanSet() { + return scope.errorf("Cannot set dest. (Tried to deep copy something with unexported fields?)") + } + + if !scope.flags.IsSet(AllowDifferentFieldTypeNames) && c.nameFunc(dt) != c.nameFunc(st) { + return scope.errorf( + "type names don't match (%v, %v), and no conversion 'func (%v, %v) error' registered.", + c.nameFunc(st), c.nameFunc(dt), st, dt) + } + + switch st.Kind() { + case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct: + // Don't copy these via assignment/conversion! + default: + // This should handle all simple types. + if st.AssignableTo(dt) { + dv.Set(sv) + return nil + } + if st.ConvertibleTo(dt) { + dv.Set(sv.Convert(dt)) + return nil + } + } + + if c.Debug != nil { + c.Debug.Logf("Trying to convert '%v' to '%v'", st, dt) + } + + scope.srcStack.push(scopeStackElem{value: sv}) + scope.destStack.push(scopeStackElem{value: dv}) + defer scope.srcStack.pop() + defer scope.destStack.pop() + + switch dv.Kind() { + case reflect.Struct: + return c.convertKV(toKVValue(sv), toKVValue(dv), scope) + case reflect.Slice: + if sv.IsNil() { + // Don't make a zero-length slice. + dv.Set(reflect.Zero(dt)) + return nil + } + dv.Set(reflect.MakeSlice(dt, sv.Len(), sv.Cap())) + for i := 0; i < sv.Len(); i++ { + scope.setIndices(i, i) + if err := c.convert(sv.Index(i), dv.Index(i), scope); err != nil { + return err + } + } + case reflect.Ptr: + if sv.IsNil() { + // Don't copy a nil ptr! + dv.Set(reflect.Zero(dt)) + return nil + } + dv.Set(reflect.New(dt.Elem())) + switch st.Kind() { + case reflect.Ptr, reflect.Interface: + return c.convert(sv.Elem(), dv.Elem(), scope) + default: + return c.convert(sv, dv.Elem(), scope) + } + case reflect.Map: + if sv.IsNil() { + // Don't copy a nil ptr! + dv.Set(reflect.Zero(dt)) + return nil + } + dv.Set(reflect.MakeMap(dt)) + for _, sk := range sv.MapKeys() { + dk := reflect.New(dt.Key()).Elem() + if err := c.convert(sk, dk, scope); err != nil { + return err + } + dkv := reflect.New(dt.Elem()).Elem() + scope.setKeys(sk.Interface(), dk.Interface()) + // TODO: sv.MapIndex(sk) may return a value with CanAddr() == false, + // because a map[string]struct{} does not allow a pointer reference. + // Calling a custom conversion function defined for the map value + // will panic. Example is PodInfo map[string]ContainerStatus. + if err := c.convert(sv.MapIndex(sk), dkv, scope); err != nil { + return err + } + dv.SetMapIndex(dk, dkv) + } + case reflect.Interface: + if sv.IsNil() { + // Don't copy a nil interface! + dv.Set(reflect.Zero(dt)) + return nil + } + tmpdv := reflect.New(sv.Elem().Type()).Elem() + if err := c.convert(sv.Elem(), tmpdv, scope); err != nil { + return err + } + dv.Set(reflect.ValueOf(tmpdv.Interface())) + return nil + default: + return scope.errorf("couldn't copy '%v' into '%v'; didn't understand types", st, dt) + } + return nil +} + +var stringType = reflect.TypeOf("") + +func toKVValue(v reflect.Value) kvValue { + switch v.Kind() { + case reflect.Struct: + return structAdaptor(v) + case reflect.Map: + if v.Type().Key().AssignableTo(stringType) { + return stringMapAdaptor(v) + } + } + + return nil +} + +// kvValue lets us write the same conversion logic to work with both maps +// and structs. Only maps with string keys make sense for this. +type kvValue interface { + // returns all keys, as a []string. + keys() []string + // Will just return "" for maps. + tagOf(key string) reflect.StructTag + // Will return the zero Value if the key doesn't exist. + value(key string) reflect.Value + // Maps require explicit setting-- will do nothing for structs. + // Returns false on failure. + confirmSet(key string, v reflect.Value) bool +} + +type stringMapAdaptor reflect.Value + +func (a stringMapAdaptor) len() int { + return reflect.Value(a).Len() +} + +func (a stringMapAdaptor) keys() []string { + v := reflect.Value(a) + keys := make([]string, v.Len()) + for i, v := range v.MapKeys() { + if v.IsNil() { + continue + } + switch t := v.Interface().(type) { + case string: + keys[i] = t + } + } + return keys +} + +func (a stringMapAdaptor) tagOf(key string) reflect.StructTag { + return "" +} + +func (a stringMapAdaptor) value(key string) reflect.Value { + return reflect.Value(a).MapIndex(reflect.ValueOf(key)) +} + +func (a stringMapAdaptor) confirmSet(key string, v reflect.Value) bool { + return true +} + +type structAdaptor reflect.Value + +func (a structAdaptor) len() int { + v := reflect.Value(a) + return v.Type().NumField() +} + +func (a structAdaptor) keys() []string { + v := reflect.Value(a) + t := v.Type() + keys := make([]string, t.NumField()) + for i := range keys { + keys[i] = t.Field(i).Name + } + return keys +} + +func (a structAdaptor) tagOf(key string) reflect.StructTag { + v := reflect.Value(a) + field, ok := v.Type().FieldByName(key) + if ok { + return field.Tag + } + return "" +} + +func (a structAdaptor) value(key string) reflect.Value { + v := reflect.Value(a) + return v.FieldByName(key) +} + +func (a structAdaptor) confirmSet(key string, v reflect.Value) bool { + return true +} + +// convertKV can convert things that consist of key/value pairs, like structs +// and some maps. +func (c *Converter) convertKV(skv, dkv kvValue, scope *scope) error { + if skv == nil || dkv == nil { + // TODO: add keys to stack to support really understandable error messages. + return fmt.Errorf("Unable to convert %#v to %#v", skv, dkv) + } + + lister := dkv + if scope.flags.IsSet(SourceToDest) { + lister = skv + } + + var mapping FieldMappingFunc + if scope.meta != nil && scope.meta.KeyNameMapping != nil { + mapping = scope.meta.KeyNameMapping + } + + for _, key := range lister.keys() { + if found, err := c.checkField(key, skv, dkv, scope); found { + if err != nil { + return err + } + continue + } + stag := skv.tagOf(key) + dtag := dkv.tagOf(key) + skey := key + dkey := key + if mapping != nil { + skey, dkey = scope.meta.KeyNameMapping(key, stag, dtag) + } + + df := dkv.value(dkey) + sf := skv.value(skey) + if !df.IsValid() || !sf.IsValid() { + switch { + case scope.flags.IsSet(IgnoreMissingFields): + // No error. + case scope.flags.IsSet(SourceToDest): + return scope.errorf("%v not present in dest", dkey) + default: + return scope.errorf("%v not present in src", skey) + } + continue + } + scope.srcStack.top().key = skey + scope.srcStack.top().tag = stag + scope.destStack.top().key = dkey + scope.destStack.top().tag = dtag + if err := c.convert(sf, df, scope); err != nil { + return err + } + } + return nil +} + +// checkField returns true if the field name matches any of the struct +// field copying rules. The error should be ignored if it returns false. +func (c *Converter) checkField(fieldName string, skv, dkv kvValue, scope *scope) (bool, error) { + replacementMade := false + if scope.flags.IsSet(DestFromSource) { + df := dkv.value(fieldName) + if !df.IsValid() { + return false, nil + } + destKey := typeNamePair{df.Type(), fieldName} + // Check each of the potential source (type, name) pairs to see if they're + // present in sv. + for _, potentialSourceKey := range c.structFieldSources[destKey] { + sf := skv.value(potentialSourceKey.fieldName) + if !sf.IsValid() { + continue + } + if sf.Type() == potentialSourceKey.fieldType { + // Both the source's name and type matched, so copy. + scope.srcStack.top().key = potentialSourceKey.fieldName + scope.destStack.top().key = fieldName + if err := c.convert(sf, df, scope); err != nil { + return true, err + } + dkv.confirmSet(fieldName, df) + replacementMade = true + } + } + return replacementMade, nil + } + + sf := skv.value(fieldName) + if !sf.IsValid() { + return false, nil + } + srcKey := typeNamePair{sf.Type(), fieldName} + // Check each of the potential dest (type, name) pairs to see if they're + // present in dv. + for _, potentialDestKey := range c.structFieldDests[srcKey] { + df := dkv.value(potentialDestKey.fieldName) + if !df.IsValid() { + continue + } + if df.Type() == potentialDestKey.fieldType { + // Both the dest's name and type matched, so copy. + scope.srcStack.top().key = fieldName + scope.destStack.top().key = potentialDestKey.fieldName + if err := c.convert(sf, df, scope); err != nil { + return true, err + } + dkv.confirmSet(potentialDestKey.fieldName, df) + replacementMade = true + } + } + return replacementMade, nil +} diff --git a/vendor/github.com/kubernetes/apimachinery/pkg/conversion/deep_equal.go b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/deep_equal.go new file mode 100644 index 000000000..f21abe1e5 --- /dev/null +++ b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/deep_equal.go @@ -0,0 +1,36 @@ +/* +Copyright 2015 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 conversion + +import ( + "k8s.io/apimachinery/third_party/forked/golang/reflect" +) + +// The code for this type must be located in third_party, since it forks from +// go std lib. But for convenience, we expose the type here, too. +type Equalities struct { + reflect.Equalities +} + +// For convenience, panics on errors +func EqualitiesOrDie(funcs ...interface{}) Equalities { + e := Equalities{reflect.Equalities{}} + if err := e.AddFuncs(funcs...); err != nil { + panic(err) + } + return e +} diff --git a/vendor/github.com/kubernetes/apimachinery/pkg/conversion/doc.go b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/doc.go new file mode 100644 index 000000000..7415d8164 --- /dev/null +++ b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2014 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 conversion provides go object versioning. +// +// Specifically, conversion provides a way for you to define multiple versions +// of the same object. You may write functions which implement conversion logic, +// but for the fields which did not change, copying is automated. This makes it +// easy to modify the structures you use in memory without affecting the format +// you store on disk or respond to in your external API calls. +package conversion // import "k8s.io/apimachinery/pkg/conversion" diff --git a/vendor/github.com/kubernetes/apimachinery/pkg/conversion/helper.go b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/helper.go new file mode 100644 index 000000000..4ebc1ebc5 --- /dev/null +++ b/vendor/github.com/kubernetes/apimachinery/pkg/conversion/helper.go @@ -0,0 +1,39 @@ +/* +Copyright 2014 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 conversion + +import ( + "fmt" + "reflect" +) + +// EnforcePtr ensures that obj is a pointer of some sort. Returns a reflect.Value +// of the dereferenced pointer, ensuring that it is settable/addressable. +// Returns an error if this is not possible. +func EnforcePtr(obj interface{}) (reflect.Value, error) { + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + if v.Kind() == reflect.Invalid { + return reflect.Value{}, fmt.Errorf("expected pointer, but got invalid kind") + } + return reflect.Value{}, fmt.Errorf("expected pointer, but got %v type", v.Type()) + } + if v.IsNil() { + return reflect.Value{}, fmt.Errorf("expected pointer, but got nil") + } + return v.Elem(), nil +}