From c20293e5319e1ae4e92fe230678151c72fd91e68 Mon Sep 17 00:00:00 2001 From: TimTheSinner Date: Mon, 21 Jan 2019 21:45:51 -0700 Subject: [PATCH] Support custom resources (#215) Notes: - Created an ExtendedClientset allowing generic access to K8S REST client - Refactored all usage of the provider to the K8S interfaces - Added a dependency on "github.com/ghodss/yaml" - Handle create, update, delete for custom resources - Custom resource update state delta between K8S, TF, and Desired is handled through transient fields --- kubernetes/custom_resource_client.go | 239 +++++++++ kubernetes/event_helpers.go | 2 +- kubernetes/provider.go | 18 +- kubernetes/resource_custom.go | 290 ++++++++++ ...esource_kubernetes_cluster_role_binding.go | 10 +- kubernetes/resource_kubernetes_config_map.go | 10 +- kubernetes/resource_kubernetes_deployment.go | 12 +- ...ce_kubernetes_horizontal_pod_autoscaler.go | 10 +- kubernetes/resource_kubernetes_limit_range.go | 10 +- kubernetes/resource_kubernetes_namespace.go | 10 +- .../resource_kubernetes_network_policy.go | 10 +- .../resource_kubernetes_persistent_volume.go | 13 +- ...urce_kubernetes_persistent_volume_claim.go | 10 +- kubernetes/resource_kubernetes_pod.go | 10 +- ...ource_kubernetes_replication_controller.go | 12 +- .../resource_kubernetes_resource_quota.go | 10 +- kubernetes/resource_kubernetes_role.go | 13 +- .../resource_kubernetes_role_binding.go | 13 +- kubernetes/resource_kubernetes_secret.go | 10 +- kubernetes/resource_kubernetes_service.go | 13 +- .../resource_kubernetes_service_account.go | 10 +- .../resource_kubernetes_stateful_set.go | 10 +- .../resource_kubernetes_storage_class.go | 10 +- vendor/github.com/ghodss/yaml/LICENSE | 50 ++ vendor/github.com/ghodss/yaml/README.md | 121 +++++ vendor/github.com/ghodss/yaml/fields.go | 501 ++++++++++++++++++ vendor/github.com/ghodss/yaml/yaml.go | 305 +++++++++++ vendor/github.com/ghodss/yaml/yaml_go110.go | 14 + .../github.com/ghodss/yaml/yaml_go110_test.go | 46 ++ vendor/github.com/ghodss/yaml/yaml_test.go | 300 +++++++++++ vendor/vendor.json | 13 + 31 files changed, 2002 insertions(+), 103 deletions(-) create mode 100644 kubernetes/custom_resource_client.go create mode 100644 kubernetes/resource_custom.go create mode 100644 vendor/github.com/ghodss/yaml/LICENSE create mode 100644 vendor/github.com/ghodss/yaml/README.md create mode 100644 vendor/github.com/ghodss/yaml/fields.go create mode 100644 vendor/github.com/ghodss/yaml/yaml.go create mode 100644 vendor/github.com/ghodss/yaml/yaml_go110.go create mode 100644 vendor/github.com/ghodss/yaml/yaml_go110_test.go create mode 100644 vendor/github.com/ghodss/yaml/yaml_test.go create mode 100644 vendor/vendor.json diff --git a/kubernetes/custom_resource_client.go b/kubernetes/custom_resource_client.go new file mode 100644 index 0000000000..9c782a6af6 --- /dev/null +++ b/kubernetes/custom_resource_client.go @@ -0,0 +1,239 @@ +package kubernetes + +import ( + "encoding/json" + "fmt" + "log" + "strings" + + "github.com/ghodss/yaml" + flat "github.com/hashicorp/terraform/flatmap" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + pkgApi "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + rest "k8s.io/client-go/rest" +) + +type GenericKubernetesObject struct { + *runtime.Unknown + RawJSON map[string]interface{} + ObjectMeta *metav1.ObjectMeta + GenericID *GenericObjectID +} + +func (obj *GenericKubernetesObject) FlattenedSpec() map[string]string { + processedSpec := obj.RawJSON["spec"].(map[string]interface{}) + return flat.Flatten(processedSpec) +} + +func (obj *GenericKubernetesObject) YamlSpec() string { + processedSpec := obj.RawJSON["spec"].(map[string]interface{}) + bytes, _ := yaml.Marshal(processedSpec) + return string(bytes) +} + +func (obj *GenericKubernetesObject) ID() string { + return obj.GenericID.ID() +} + +type GenericObjectID struct { + Group string + Version string + Kind string + Namespace string + Name string +} + +func genericObjectID(id, kind string) *GenericObjectID { + if strings.TrimSpace(id) == "" { + return nil + } + + parts := strings.SplitN(strings.TrimSpace(id), "/", 4) + + genericID := &GenericObjectID{ + Group: parts[0], + Version: parts[1], + Kind: kind, + } + + if len(parts) == 3 { + genericID.Name = parts[2] + } else if len(parts) == 4 { + genericID.Namespace = parts[2] + genericID.Name = parts[3] + } + + return genericID +} + +func (id *GenericObjectID) ApiVersion() string { + return fmt.Sprintf("%s/%s", id.Group, id.Version) +} + +func (id *GenericObjectID) Resource() string { + return fmt.Sprintf("%ss", strings.ToLower(id.Kind)) +} + +func (id *GenericObjectID) ID() string { + idString := make([]string, 1) + idString[0] = id.ApiVersion() + if id.Namespace != "" { + idString = append(idString, id.Namespace) + } + + return strings.Join(append(idString, id.Name), "/") +} + +type CustomResourceClient struct { + config *rest.Config +} + +// NewForConfig creates a new AdmissionregistrationV1alpha1Client for the given config. +func NewCustomResourceClient(c *rest.Config) (*CustomResourceClient, error) { + configShallowCopy := *c + return &CustomResourceClient{&configShallowCopy}, nil +} + +func (c *CustomResourceClient) setConfigDefaults(target *GenericObjectID) rest.Config { + configShallowCopy := *c.config + configShallowCopy.GroupVersion = &schema.GroupVersion{Group: target.Group, Version: target.Version} + configShallowCopy.APIPath = "/apis" + configShallowCopy.ContentType = runtime.ContentTypeJSON + configShallowCopy.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + return configShallowCopy +} + +func (c *CustomResourceClient) client(target *GenericObjectID) (rest.Interface, error) { + config := c.setConfigDefaults(target) + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return client, nil +} + +func (result *GenericKubernetesObject) process() error { + rawJSON := map[string]interface{}{} + err := json.Unmarshal(result.Raw, &rawJSON) + if err != nil { + return err + } + result.RawJSON = rawJSON + + metadata, err := json.Marshal(result.RawJSON["metadata"]) + if err != nil { + return err + } + + objectMeta := metav1.ObjectMeta{} + err = json.Unmarshal(metadata, &objectMeta) + if err != nil { + return err + } + + result.ObjectMeta = &objectMeta + result.GenericID = genericObjectID(result.RawJSON["apiVersion"].(string), result.RawJSON["kind"].(string)) + result.GenericID.Name = objectMeta.Name + result.GenericID.Namespace = objectMeta.Namespace + + return nil +} + +func (c *CustomResourceClient) request(target *GenericObjectID, request *rest.Request) *rest.Request { + if target.Namespace != "" { + return request.Resource(target.Resource()).Namespace(target.Namespace) + } + return request.Resource(target.Resource()) +} + +func (c *CustomResourceClient) Get(target *GenericObjectID) (result *GenericKubernetesObject, err error) { + client, err := c.client(target) + if err != nil { + return nil, err + } + + rawResult := runtime.Unknown{} + err = c.request(target, client.Get()). + Name(target.Name). + Do(). + Into(&rawResult) + + if err != nil { + return + } + + result = &GenericKubernetesObject{Unknown: &rawResult} + result.process() + return +} + +func (c *CustomResourceClient) Delete(target *GenericObjectID) (err error) { + client, err := c.client(target) + if err != nil { + return err + } + + return c.request(target, client.Delete()). + Name(target.Name). + Do(). + Error() +} + +func (c *CustomResourceClient) Create(target *GenericObjectID, obj map[string]interface{}) (result *GenericKubernetesObject, err error) { + client, err := c.client(target) + if err != nil { + return nil, err + } + + raw, err := json.Marshal(obj) + if err != nil { + return nil, err + } + + rawResult := runtime.Unknown{} + err = c.request(target, client.Post()). + Body(raw). + Do(). + Into(&rawResult) + + if err != nil { + return + } + + result = &GenericKubernetesObject{Unknown: &rawResult} + result.process() + return +} + +func (c *CustomResourceClient) Update(target *GenericObjectID, ops PatchOperations) (result *GenericKubernetesObject, err error) { + client, err := c.client(target) + if err != nil { + return nil, err + } + + data, err := ops.MarshalJSON() + if err != nil { + return nil, fmt.Errorf("Failed to marshal update operations: %s", err) + } + + log.Printf("[INFO] Updating custom %s: %s", target.ID(), string(data)) + + rawResult := runtime.Unknown{} + err = c.request(target, client.Patch(pkgApi.JSONPatchType)). + Name(target.Name). + Body(data). + Do(). + Into(&rawResult) + + if err != nil { + return + } + + result = &GenericKubernetesObject{Unknown: &rawResult} + result.process() + return +} diff --git a/kubernetes/event_helpers.go b/kubernetes/event_helpers.go index 848b825948..1798ccbdd2 100644 --- a/kubernetes/event_helpers.go +++ b/kubernetes/event_helpers.go @@ -11,7 +11,7 @@ import ( kubernetes "k8s.io/client-go/kubernetes" ) -func getLastWarningsForObject(conn *kubernetes.Clientset, metadata meta_v1.ObjectMeta, kind string, limit int) ([]api.Event, error) { +func getLastWarningsForObject(conn kubernetes.Interface, metadata meta_v1.ObjectMeta, kind string, limit int) ([]api.Event, error) { m := map[string]string{ "involvedObject.name": metadata.Name, "involvedObject.kind": kind, diff --git a/kubernetes/provider.go b/kubernetes/provider.go index 9262f8397a..f82579c587 100644 --- a/kubernetes/provider.go +++ b/kubernetes/provider.go @@ -16,6 +16,16 @@ import ( clientcmdapi "k8s.io/client-go/tools/clientcmd/api" ) +type ExtendedClientset struct { + *kubernetes.Clientset + customResource *CustomResourceClient +} + +// la la connect the dots +func (c *ExtendedClientset) CustomResource() *CustomResourceClient { + return c.customResource +} + func Provider() terraform.ResourceProvider { return &schema.Provider{ Schema: map[string]*schema.Schema{ @@ -115,6 +125,7 @@ func Provider() terraform.ResourceProvider { "kubernetes_config_map": resourceKubernetesConfigMap(), "kubernetes_daemonset": resourceKubernetesDaemonSet(), "kubernetes_deployment": resourceKubernetesDeployment(), + "kubernetes_generic": resourceKubernetesCustom(), "kubernetes_horizontal_pod_autoscaler": resourceKubernetesHorizontalPodAutoscaler(), "kubernetes_limit_range": resourceKubernetesLimitRange(), "kubernetes_namespace": resourceKubernetesNamespace(), @@ -185,7 +196,12 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { return nil, fmt.Errorf("Failed to configure: %s", err) } - return k, nil + rest, err := NewCustomResourceClient(cfg) + if err != nil { + return nil, fmt.Errorf("Failed to configure: %s", err) + } + + return ExtendedClientset{Clientset: k, customResource: rest}, nil } func tryLoadingConfigFile(d *schema.ResourceData) (*restclient.Config, error) { diff --git a/kubernetes/resource_custom.go b/kubernetes/resource_custom.go new file mode 100644 index 0000000000..c4ab6c8be2 --- /dev/null +++ b/kubernetes/resource_custom.go @@ -0,0 +1,290 @@ +package kubernetes + +import ( + "fmt" + "log" + "strings" + "time" + + flat "github.com/hashicorp/terraform/flatmap" + "github.com/hashicorp/terraform/helper/schema" + apiErrors "k8s.io/apimachinery/pkg/api/errors" + + "github.com/ghodss/yaml" +) + +const ( + customResourceEditAddPrefix = "transitent-add." + customResourceEditUpdatePrefix = "transitent-update." + customResourceEditDeletePrefix = "transitent-delete." +) + +func resourceKubernetesCustom() *schema.Resource { + return &schema.Resource{ + Create: resourceKubernetesCustomCreate, + Read: resourceKubernetesCustomRead, + Update: resourceKubernetesCustomUpdate, + Delete: resourceKubernetesCustomDelete, + Exists: resourceKubernetesCustomExists, + + CustomizeDiff: resourceKubernetesCustomDiff, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "API Version of the custom resource", + }, + "kind": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The formal type of the custom resource", + }, + "metadata": &schema.Schema{ + Type: schema.TypeList, + Description: fmt.Sprintf("Standard GenericResource's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#metadata"), + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: metadataFields("GenericResource"), + }, + }, + "yaml": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Resource spec as raw yaml, this configuration is merged with spec map.", + }, + "spec": { + Type: schema.TypeMap, + Description: "Specification of the desired behavior of the custom resource.", + Computed: true, + }, + }, + } +} + +func getCustomResourceFromKubernetes(id, kind string, meta interface{}) (*GenericKubernetesObject, error) { + conn := meta.(ExtendedClientset) + + genericID := genericObjectID(id, kind) + if genericID == nil { + return nil, nil + } + + if genericID.Namespace == "" { + log.Printf("[INFO] Checking custom %s\n", genericID.Name) + } else { + log.Printf("[INFO] Checking custom %s in %s\n", genericID.Name, genericID.Namespace) + } + + result, err := conn.CustomResource().Get(genericID) + if err != nil { + log.Printf("[DEBUG] Received error: %#v", err) + return nil, err + } + return result, err +} + +func resourceKubernetesCustomCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(ExtendedClientset) + + metadata := expandMetadata(d.Get("metadata").([]interface{})) + genericID := genericObjectID(d.Get("api_version").(string), d.Get("kind").(string)) + + base := map[string]interface{}{ + "kind": genericID.Kind, + "apiVersion": genericID.ApiVersion(), + "metadata": map[string]interface{}{ + "name": metadata.Name, + }, + } + + spec := map[string]interface{}{} + base["spec"] = spec + + yamlSpec := d.Get("yaml").(string) + if err := yaml.Unmarshal([]byte(yamlSpec), &spec); err != nil { + return fmt.Errorf("---> %v %s", err, yamlSpec) + } + + result, err := conn.CustomResource().Create(genericID, base) + if err != nil { + return err + } + + d.SetId(result.ID()) + + err = d.Set("spec", result.FlattenedSpec()) + if err != nil { + return err + } + + err = d.Set("metadata", flattenMetadata(*result.ObjectMeta)) + if err != nil { + return err + } + + log.Printf("[INFO] Created new custom: %#v", d) + return nil +} + +func resourceKubernetesCustomDiff(d *schema.ResourceDiff, meta interface{}) error { + resource, err := getCustomResourceFromKubernetes(d.Id(), d.Get("kind").(string), meta) + if resource == nil { + return nil + } else if err != nil { + return err + } + + fullSpec := map[string]interface{}{} + err = yaml.Unmarshal([]byte(d.Get("yaml").(string)), &fullSpec) + if err != nil { + return err + } + + desiredSpec := flat.Flatten(fullSpec) + kubernetesSpec := resource.FlattenedSpec() + + deletedSpec := map[string]string{} + for key, value := range kubernetesSpec { + if _, ok := desiredSpec[key]; !ok { + deletedSpec[key] = fmt.Sprintf("'%s' --> ''", value) + } + } + + for k, v := range deletedSpec { + kubernetesSpec[fmt.Sprintf("%s%s", customResourceEditDeletePrefix, k)] = v + delete(kubernetesSpec, k) + } + + for key, value := range desiredSpec { + if kube, ok := kubernetesSpec[key]; !ok { + kubernetesSpec[key] = value + kubernetesSpec[fmt.Sprintf("%s%s", customResourceEditAddPrefix, key)] = value + } else if value != kube { + kubernetesSpec[key] = value + kubernetesSpec[fmt.Sprintf("%s%s", customResourceEditUpdatePrefix, key)] = fmt.Sprintf("'%s' --> '%s'", kube, value) + } + } + + err = d.SetNew("spec", kubernetesSpec) + if err != nil { + return err + } + + return nil +} + +func resourceKubernetesCustomUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(ExtendedClientset) + + genericID := genericObjectID(d.Id(), d.Get("kind").(string)) + ops := patchMetadata("metadata.0.", "/metadata/", d) + + if d.HasChange("spec") { + spec := d.Get("spec").(map[string]interface{}) + for k := range spec { + if strings.HasPrefix(k, customResourceEditAddPrefix) { + key := strings.Replace(k, customResourceEditAddPrefix, "", 1) + ops = append(ops, &AddOperation{ + Path: fmt.Sprintf("/spec/%s", strings.Replace(key, ".", "/", -1)), + Value: spec[key], + }) + } else if strings.HasPrefix(k, customResourceEditUpdatePrefix) { + key := strings.Replace(k, customResourceEditUpdatePrefix, "", 1) + ops = append(ops, &ReplaceOperation{ + Path: fmt.Sprintf("/spec/%s", strings.Replace(key, ".", "/", -1)), + Value: spec[key], + }) + } else if strings.HasPrefix(k, customResourceEditDeletePrefix) { + ops = append(ops, &RemoveOperation{ + Path: strings.Replace(strings.Replace(k, customResourceEditDeletePrefix, "/spec/", 1), ".", "/", -1), + }) + } + } + } + + result, err := conn.CustomResource().Update(genericID, ops) + if err != nil { + return err + } + + d.SetId(result.ID()) + + err = d.Set("spec", result.FlattenedSpec()) + if err != nil { + return err + } + + err = d.Set("metadata", flattenMetadata(*result.ObjectMeta)) + if err != nil { + return err + } + + return nil +} + +func resourceKubernetesCustomRead(d *schema.ResourceData, meta interface{}) error { + result, err := getCustomResourceFromKubernetes(d.Id(), d.Get("kind").(string), meta) + if err != nil { + return err + } + + d.SetId(result.ID()) + + err = d.Set("metadata", flattenMetadata(*result.ObjectMeta)) + if err != nil { + return err + } + + return nil +} + +func resourceKubernetesCustomDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(ExtendedClientset) + + genericID := genericObjectID(d.Id(), d.Get("kind").(string)) + err := conn.CustomResource().Delete(genericID) + if err != nil { + log.Printf("[DEBUG] Received error: %#v", err) + return err + } + + d.SetId("") + log.Printf("[INFO] Deleted %s", genericID.ID()) + + return nil +} + +func resourceKubernetesCustomExists(d *schema.ResourceData, meta interface{}) (bool, error) { + conn := meta.(ExtendedClientset) + + genericID := genericObjectID(d.Id(), d.Get("kind").(string)) + if genericID == nil { + return false, nil + } + + if genericID.Namespace == "" { + log.Printf("[INFO] Checking custom %s\n", genericID.Name) + } else { + log.Printf("[INFO] Checking custom %s in %s\n", genericID.Name, genericID.Namespace) + } + + _, err := conn.CustomResource().Get(genericID) + if err != nil { + if statusErr, ok := err.(*apiErrors.StatusError); ok && statusErr.ErrStatus.Code == 404 { + return false, nil + } + log.Printf("[DEBUG] Received error: %#v", err) + } + return true, err +} diff --git a/kubernetes/resource_kubernetes_cluster_role_binding.go b/kubernetes/resource_kubernetes_cluster_role_binding.go index f7d915784b..b136c548ff 100644 --- a/kubernetes/resource_kubernetes_cluster_role_binding.go +++ b/kubernetes/resource_kubernetes_cluster_role_binding.go @@ -48,7 +48,7 @@ func resourceKubernetesClusterRoleBinding() *schema.Resource { } func resourceKubernetesClusterRoleBindingCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) binding := &api.ClusterRoleBinding{ @@ -69,7 +69,7 @@ func resourceKubernetesClusterRoleBindingCreate(d *schema.ResourceData, meta int } func resourceKubernetesClusterRoleBindingRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Reading ClusterRoleBinding %s", name) @@ -103,7 +103,7 @@ func resourceKubernetesClusterRoleBindingRead(d *schema.ResourceData, meta inter } func resourceKubernetesClusterRoleBindingUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() @@ -128,7 +128,7 @@ func resourceKubernetesClusterRoleBindingUpdate(d *schema.ResourceData, meta int } func resourceKubernetesClusterRoleBindingDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Deleting ClusterRoleBinding: %#v", name) @@ -143,7 +143,7 @@ func resourceKubernetesClusterRoleBindingDelete(d *schema.ResourceData, meta int } func resourceKubernetesClusterRoleBindingExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Checking ClusterRoleBinding %s", name) diff --git a/kubernetes/resource_kubernetes_config_map.go b/kubernetes/resource_kubernetes_config_map.go index 9ed6bf6537..e2f5fb481c 100644 --- a/kubernetes/resource_kubernetes_config_map.go +++ b/kubernetes/resource_kubernetes_config_map.go @@ -35,7 +35,7 @@ func resourceKubernetesConfigMap() *schema.Resource { } func resourceKubernetesConfigMapCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) cfgMap := api.ConfigMap{ @@ -54,7 +54,7 @@ func resourceKubernetesConfigMapCreate(d *schema.ResourceData, meta interface{}) } func resourceKubernetesConfigMapRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -77,7 +77,7 @@ func resourceKubernetesConfigMapRead(d *schema.ResourceData, meta interface{}) e } func resourceKubernetesConfigMapUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -106,7 +106,7 @@ func resourceKubernetesConfigMapUpdate(d *schema.ResourceData, meta interface{}) } func resourceKubernetesConfigMapDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -125,7 +125,7 @@ func resourceKubernetesConfigMapDelete(d *schema.ResourceData, meta interface{}) } func resourceKubernetesConfigMapExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_deployment.go b/kubernetes/resource_kubernetes_deployment.go index 97eee0bd16..5d786efe39 100644 --- a/kubernetes/resource_kubernetes_deployment.go +++ b/kubernetes/resource_kubernetes_deployment.go @@ -186,7 +186,7 @@ func resourceKubernetesDeployment() *schema.Resource { } func resourceKubernetesDeploymentCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) spec, err := expandDeploymentSpec(d.Get("spec").([]interface{})) @@ -224,7 +224,7 @@ func resourceKubernetesDeploymentCreate(d *schema.ResourceData, meta interface{} } func resourceKubernetesDeploymentUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -265,7 +265,7 @@ func resourceKubernetesDeploymentUpdate(d *schema.ResourceData, meta interface{} } func resourceKubernetesDeploymentRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -299,7 +299,7 @@ func resourceKubernetesDeploymentRead(d *schema.ResourceData, meta interface{}) } func resourceKubernetesDeploymentDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -320,7 +320,7 @@ func resourceKubernetesDeploymentDelete(d *schema.ResourceData, meta interface{} } func resourceKubernetesDeploymentExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -350,7 +350,7 @@ func GetDeploymentCondition(status appsv1.DeploymentStatus, condType appsv1.Depl return nil } -func waitForDeploymentReplicasFunc(conn *kubernetes.Clientset, ns, name string) resource.RetryFunc { +func waitForDeploymentReplicasFunc(conn kubernetes.Interface, ns, name string) resource.RetryFunc { return func() *resource.RetryError { // Query the deployment to get a status update. dply, err := conn.AppsV1().Deployments(ns).Get(name, metav1.GetOptions{}) diff --git a/kubernetes/resource_kubernetes_horizontal_pod_autoscaler.go b/kubernetes/resource_kubernetes_horizontal_pod_autoscaler.go index 95eeb7af7b..d12d0a1d7b 100644 --- a/kubernetes/resource_kubernetes_horizontal_pod_autoscaler.go +++ b/kubernetes/resource_kubernetes_horizontal_pod_autoscaler.go @@ -82,7 +82,7 @@ func resourceKubernetesHorizontalPodAutoscaler() *schema.Resource { } func resourceKubernetesHorizontalPodAutoscalerCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) spec, err := expandHorizontalPodAutoscalerSpec(d.Get("spec").([]interface{})) @@ -107,7 +107,7 @@ func resourceKubernetesHorizontalPodAutoscalerCreate(d *schema.ResourceData, met } func resourceKubernetesHorizontalPodAutoscalerRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -136,7 +136,7 @@ func resourceKubernetesHorizontalPodAutoscalerRead(d *schema.ResourceData, meta } func resourceKubernetesHorizontalPodAutoscalerUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -164,7 +164,7 @@ func resourceKubernetesHorizontalPodAutoscalerUpdate(d *schema.ResourceData, met } func resourceKubernetesHorizontalPodAutoscalerDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -183,7 +183,7 @@ func resourceKubernetesHorizontalPodAutoscalerDelete(d *schema.ResourceData, met } func resourceKubernetesHorizontalPodAutoscalerExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_limit_range.go b/kubernetes/resource_kubernetes_limit_range.go index 4f0384d0c6..d232e0d06a 100644 --- a/kubernetes/resource_kubernetes_limit_range.go +++ b/kubernetes/resource_kubernetes_limit_range.go @@ -80,7 +80,7 @@ func resourceKubernetesLimitRange() *schema.Resource { } func resourceKubernetesLimitRangeCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) spec, err := expandLimitRangeSpec(d.Get("spec").([]interface{}), d.IsNewResource()) @@ -103,7 +103,7 @@ func resourceKubernetesLimitRangeCreate(d *schema.ResourceData, meta interface{} } func resourceKubernetesLimitRangeRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -130,7 +130,7 @@ func resourceKubernetesLimitRangeRead(d *schema.ResourceData, meta interface{}) } func resourceKubernetesLimitRangeUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -164,7 +164,7 @@ func resourceKubernetesLimitRangeUpdate(d *schema.ResourceData, meta interface{} } func resourceKubernetesLimitRangeDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -184,7 +184,7 @@ func resourceKubernetesLimitRangeDelete(d *schema.ResourceData, meta interface{} } func resourceKubernetesLimitRangeExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_namespace.go b/kubernetes/resource_kubernetes_namespace.go index 91fb86615f..86137e7213 100644 --- a/kubernetes/resource_kubernetes_namespace.go +++ b/kubernetes/resource_kubernetes_namespace.go @@ -32,7 +32,7 @@ func resourceKubernetesNamespace() *schema.Resource { } func resourceKubernetesNamespaceCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) namespace := api.Namespace{ @@ -50,7 +50,7 @@ func resourceKubernetesNamespaceCreate(d *schema.ResourceData, meta interface{}) } func resourceKubernetesNamespaceRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Reading namespace %s", name) @@ -69,7 +69,7 @@ func resourceKubernetesNamespaceRead(d *schema.ResourceData, meta interface{}) e } func resourceKubernetesNamespaceUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) ops := patchMetadata("metadata.0.", "/metadata/", d) data, err := ops.MarshalJSON() @@ -89,7 +89,7 @@ func resourceKubernetesNamespaceUpdate(d *schema.ResourceData, meta interface{}) } func resourceKubernetesNamespaceDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Deleting namespace: %#v", name) @@ -128,7 +128,7 @@ func resourceKubernetesNamespaceDelete(d *schema.ResourceData, meta interface{}) } func resourceKubernetesNamespaceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Checking namespace %s", name) diff --git a/kubernetes/resource_kubernetes_network_policy.go b/kubernetes/resource_kubernetes_network_policy.go index 43bedf9aac..71eaa93f54 100644 --- a/kubernetes/resource_kubernetes_network_policy.go +++ b/kubernetes/resource_kubernetes_network_policy.go @@ -236,7 +236,7 @@ func resourceKubernetesNetworkPolicy() *schema.Resource { } func resourceKubernetesNetworkPolicyCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) spec, err := expandNetworkPolicySpec(d.Get("spec").([]interface{})) @@ -261,7 +261,7 @@ func resourceKubernetesNetworkPolicyCreate(d *schema.ResourceData, meta interfac } func resourceKubernetesNetworkPolicyRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -290,7 +290,7 @@ func resourceKubernetesNetworkPolicyRead(d *schema.ResourceData, meta interface{ } func resourceKubernetesNetworkPolicyUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -321,7 +321,7 @@ func resourceKubernetesNetworkPolicyUpdate(d *schema.ResourceData, meta interfac } func resourceKubernetesNetworkPolicyDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -339,7 +339,7 @@ func resourceKubernetesNetworkPolicyDelete(d *schema.ResourceData, meta interfac } func resourceKubernetesNetworkPolicyExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_persistent_volume.go b/kubernetes/resource_kubernetes_persistent_volume.go index 793c1d52c4..d62eef5f3d 100644 --- a/kubernetes/resource_kubernetes_persistent_volume.go +++ b/kubernetes/resource_kubernetes_persistent_volume.go @@ -12,6 +12,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" pkgApi "k8s.io/apimachinery/pkg/types" + discovery "k8s.io/client-go/discovery" kubernetes "k8s.io/client-go/kubernetes" ) @@ -34,7 +35,7 @@ func resourceKubernetesPersistentVolume() *schema.Resource { // Mutation of PersistentVolumeSource after creation is no longer allowed in 1.9+ // See https://github.com/kubernetes/kubernetes/blob/v1.9.3/CHANGELOG-1.9.md#storage-3 - conn := meta.(*kubernetes.Clientset) + conn := meta.(discovery.ServerVersionInterface) serverVersion, err := conn.ServerVersion() if err != nil { return err @@ -138,7 +139,7 @@ func resourceKubernetesPersistentVolume() *schema.Resource { } func resourceKubernetesPersistentVolumeCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) spec, err := expandPersistentVolumeSpec(d.Get("spec").([]interface{})) @@ -185,7 +186,7 @@ func resourceKubernetesPersistentVolumeCreate(d *schema.ResourceData, meta inter } func resourceKubernetesPersistentVolumeRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Reading persistent volume %s", name) @@ -208,7 +209,7 @@ func resourceKubernetesPersistentVolumeRead(d *schema.ResourceData, meta interfa } func resourceKubernetesPersistentVolumeUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) ops := patchMetadata("metadata.0.", "/metadata/", d) if d.HasChange("spec") { @@ -235,7 +236,7 @@ func resourceKubernetesPersistentVolumeUpdate(d *schema.ResourceData, meta inter } func resourceKubernetesPersistentVolumeDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Deleting persistent volume: %#v", name) @@ -251,7 +252,7 @@ func resourceKubernetesPersistentVolumeDelete(d *schema.ResourceData, meta inter } func resourceKubernetesPersistentVolumeExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Checking persistent volume %s", name) diff --git a/kubernetes/resource_kubernetes_persistent_volume_claim.go b/kubernetes/resource_kubernetes_persistent_volume_claim.go index 07a351289e..a8af158681 100644 --- a/kubernetes/resource_kubernetes_persistent_volume_claim.go +++ b/kubernetes/resource_kubernetes_persistent_volume_claim.go @@ -46,7 +46,7 @@ func resourceKubernetesPersistentVolumeClaim() *schema.Resource { } func resourceKubernetesPersistentVolumeClaimCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) claim, err := expandPersistenVolumeClaim(map[string]interface{}{ "metadata": d.Get("metadata"), @@ -110,7 +110,7 @@ func resourceKubernetesPersistentVolumeClaimCreate(d *schema.ResourceData, meta } func resourceKubernetesPersistentVolumeClaimRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -137,7 +137,7 @@ func resourceKubernetesPersistentVolumeClaimRead(d *schema.ResourceData, meta in } func resourceKubernetesPersistentVolumeClaimUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -162,7 +162,7 @@ func resourceKubernetesPersistentVolumeClaimUpdate(d *schema.ResourceData, meta } func resourceKubernetesPersistentVolumeClaimDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -182,7 +182,7 @@ func resourceKubernetesPersistentVolumeClaimDelete(d *schema.ResourceData, meta } func resourceKubernetesPersistentVolumeClaimExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_pod.go b/kubernetes/resource_kubernetes_pod.go index 9074664b1b..f800fd37dd 100644 --- a/kubernetes/resource_kubernetes_pod.go +++ b/kubernetes/resource_kubernetes_pod.go @@ -45,7 +45,7 @@ func resourceKubernetesPod() *schema.Resource { } } func resourceKubernetesPodCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) spec, err := expandPodSpec(d.Get("spec").([]interface{})) @@ -100,7 +100,7 @@ func resourceKubernetesPodCreate(d *schema.ResourceData, meta interface{}) error } func resourceKubernetesPodUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -133,7 +133,7 @@ func resourceKubernetesPodUpdate(d *schema.ResourceData, meta interface{}) error } func resourceKubernetesPodRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -167,7 +167,7 @@ func resourceKubernetesPodRead(d *schema.ResourceData, meta interface{}) error { } func resourceKubernetesPodDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -204,7 +204,7 @@ func resourceKubernetesPodDelete(d *schema.ResourceData, meta interface{}) error } func resourceKubernetesPodExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_replication_controller.go b/kubernetes/resource_kubernetes_replication_controller.go index dd1bde6a2e..230402ca63 100644 --- a/kubernetes/resource_kubernetes_replication_controller.go +++ b/kubernetes/resource_kubernetes_replication_controller.go @@ -110,7 +110,7 @@ func useDeprecatedSpecFields(d *schema.ResourceData) (deprecatedSpecFieldsExist } func resourceKubernetesReplicationControllerCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) @@ -152,7 +152,7 @@ func resourceKubernetesReplicationControllerCreate(d *schema.ResourceData, meta } func resourceKubernetesReplicationControllerRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -186,7 +186,7 @@ func resourceKubernetesReplicationControllerRead(d *schema.ResourceData, meta in } func resourceKubernetesReplicationControllerUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -227,7 +227,7 @@ func resourceKubernetesReplicationControllerUpdate(d *schema.ResourceData, meta } func resourceKubernetesReplicationControllerDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -270,7 +270,7 @@ func resourceKubernetesReplicationControllerDelete(d *schema.ResourceData, meta } func resourceKubernetesReplicationControllerExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -288,7 +288,7 @@ func resourceKubernetesReplicationControllerExists(d *schema.ResourceData, meta return true, err } -func waitForDesiredReplicasFunc(conn *kubernetes.Clientset, ns, name string) resource.RetryFunc { +func waitForDesiredReplicasFunc(conn kubernetes.Interface, ns, name string) resource.RetryFunc { return func() *resource.RetryError { rc, err := conn.CoreV1().ReplicationControllers(ns).Get(name, metav1.GetOptions{}) if err != nil { diff --git a/kubernetes/resource_kubernetes_resource_quota.go b/kubernetes/resource_kubernetes_resource_quota.go index f6bf2e1280..85b1fe7847 100644 --- a/kubernetes/resource_kubernetes_resource_quota.go +++ b/kubernetes/resource_kubernetes_resource_quota.go @@ -57,7 +57,7 @@ func resourceKubernetesResourceQuota() *schema.Resource { } func resourceKubernetesResourceQuotaCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) spec, err := expandResourceQuotaSpec(d.Get("spec").([]interface{})) @@ -96,7 +96,7 @@ func resourceKubernetesResourceQuotaCreate(d *schema.ResourceData, meta interfac } func resourceKubernetesResourceQuotaRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -132,7 +132,7 @@ func resourceKubernetesResourceQuotaRead(d *schema.ResourceData, meta interface{ } func resourceKubernetesResourceQuotaUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -187,7 +187,7 @@ func resourceKubernetesResourceQuotaUpdate(d *schema.ResourceData, meta interfac } func resourceKubernetesResourceQuotaDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -207,7 +207,7 @@ func resourceKubernetesResourceQuotaDelete(d *schema.ResourceData, meta interfac } func resourceKubernetesResourceQuotaExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_role.go b/kubernetes/resource_kubernetes_role.go index d9f9a81d89..4ead8c4320 100644 --- a/kubernetes/resource_kubernetes_role.go +++ b/kubernetes/resource_kubernetes_role.go @@ -2,13 +2,14 @@ package kubernetes import ( "fmt" + "log" + "github.com/hashicorp/terraform/helper/schema" "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" pkgApi "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" - "log" ) func resourceKubernetesRole() *schema.Resource { @@ -66,7 +67,7 @@ func resourceKubernetesRole() *schema.Resource { } func resourceKubernetesRoleCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) rules := expandRules(d.Get("rule").([]interface{})) @@ -88,7 +89,7 @@ func resourceKubernetesRoleCreate(d *schema.ResourceData, meta interface{}) erro } func resourceKubernetesRoleRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -117,7 +118,7 @@ func resourceKubernetesRoleRead(d *schema.ResourceData, meta interface{}) error } func resourceKubernetesRoleUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -150,7 +151,7 @@ func resourceKubernetesRoleUpdate(d *schema.ResourceData, meta interface{}) erro } func resourceKubernetesRoleDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -169,7 +170,7 @@ func resourceKubernetesRoleDelete(d *schema.ResourceData, meta interface{}) erro } func resourceKubernetesRoleExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_role_binding.go b/kubernetes/resource_kubernetes_role_binding.go index bd1f0b5965..282df4eb58 100644 --- a/kubernetes/resource_kubernetes_role_binding.go +++ b/kubernetes/resource_kubernetes_role_binding.go @@ -2,13 +2,14 @@ package kubernetes import ( "fmt" + "log" + "github.com/hashicorp/terraform/helper/schema" api "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" pkgApi "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" - "log" ) func resourceKubernetesRoleBinding() *schema.Resource { @@ -47,7 +48,7 @@ func resourceKubernetesRoleBinding() *schema.Resource { } func resourceKubernetesRoleBindingCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) binding := &api.RoleBinding{ @@ -68,7 +69,7 @@ func resourceKubernetesRoleBindingCreate(d *schema.ResourceData, meta interface{ } func resourceKubernetesRoleBindingRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -106,7 +107,7 @@ func resourceKubernetesRoleBindingRead(d *schema.ResourceData, meta interface{}) } func resourceKubernetesRoleBindingUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -134,7 +135,7 @@ func resourceKubernetesRoleBindingUpdate(d *schema.ResourceData, meta interface{ } func resourceKubernetesRoleBindingDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -152,7 +153,7 @@ func resourceKubernetesRoleBindingDelete(d *schema.ResourceData, meta interface{ } func resourceKubernetesRoleBindingExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_secret.go b/kubernetes/resource_kubernetes_secret.go index 7ae81f0498..a69141328b 100644 --- a/kubernetes/resource_kubernetes_secret.go +++ b/kubernetes/resource_kubernetes_secret.go @@ -44,7 +44,7 @@ func resourceKubernetesSecret() *schema.Resource { } func resourceKubernetesSecretCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) secret := api.Secret{ @@ -69,7 +69,7 @@ func resourceKubernetesSecretCreate(d *schema.ResourceData, meta interface{}) er } func resourceKubernetesSecretRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -95,7 +95,7 @@ func resourceKubernetesSecretRead(d *schema.ResourceData, meta interface{}) erro } func resourceKubernetesSecretUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -132,7 +132,7 @@ func resourceKubernetesSecretUpdate(d *schema.ResourceData, meta interface{}) er } func resourceKubernetesSecretDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -153,7 +153,7 @@ func resourceKubernetesSecretDelete(d *schema.ResourceData, meta interface{}) er } func resourceKubernetesSecretExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_service.go b/kubernetes/resource_kubernetes_service.go index 3aef35454f..9713f6c5c3 100644 --- a/kubernetes/resource_kubernetes_service.go +++ b/kubernetes/resource_kubernetes_service.go @@ -11,6 +11,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" pkgApi "k8s.io/apimachinery/pkg/types" + discovery "k8s.io/client-go/discovery" kubernetes "k8s.io/client-go/kubernetes" ) @@ -150,7 +151,7 @@ func resourceKubernetesService() *schema.Resource { } func resourceKubernetesServiceCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) svc := api.Service{ @@ -198,7 +199,7 @@ func resourceKubernetesServiceCreate(d *schema.ResourceData, meta interface{}) e } func resourceKubernetesServiceRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -233,7 +234,7 @@ func resourceKubernetesServiceRead(d *schema.ResourceData, meta interface{}) err } func resourceKubernetesServiceUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -242,7 +243,7 @@ func resourceKubernetesServiceUpdate(d *schema.ResourceData, meta interface{}) e ops := patchMetadata("metadata.0.", "/metadata/", d) if d.HasChange("spec") { - serverVersion, err := conn.ServerVersion() + serverVersion, err := meta.(discovery.ServerVersionInterface).ServerVersion() if err != nil { return err } @@ -268,7 +269,7 @@ func resourceKubernetesServiceUpdate(d *schema.ResourceData, meta interface{}) e } func resourceKubernetesServiceDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -288,7 +289,7 @@ func resourceKubernetesServiceDelete(d *schema.ResourceData, meta interface{}) e } func resourceKubernetesServiceExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_service_account.go b/kubernetes/resource_kubernetes_service_account.go index ff55ef4198..55c600e301 100644 --- a/kubernetes/resource_kubernetes_service_account.go +++ b/kubernetes/resource_kubernetes_service_account.go @@ -71,7 +71,7 @@ func resourceKubernetesServiceAccount() *schema.Resource { } func resourceKubernetesServiceAccountCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) svcAcc := api.ServiceAccount{ @@ -147,7 +147,7 @@ func diffObjectReferences(origOrs []api.ObjectReference, ors []api.ObjectReferen } func resourceKubernetesServiceAccountRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -177,7 +177,7 @@ func resourceKubernetesServiceAccountRead(d *schema.ResourceData, meta interface } func resourceKubernetesServiceAccountUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -217,7 +217,7 @@ func resourceKubernetesServiceAccountUpdate(d *schema.ResourceData, meta interfa } func resourceKubernetesServiceAccountDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -237,7 +237,7 @@ func resourceKubernetesServiceAccountDelete(d *schema.ResourceData, meta interfa } func resourceKubernetesServiceAccountExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_stateful_set.go b/kubernetes/resource_kubernetes_stateful_set.go index 6d44c4e43e..6bc1790415 100644 --- a/kubernetes/resource_kubernetes_stateful_set.go +++ b/kubernetes/resource_kubernetes_stateful_set.go @@ -41,7 +41,7 @@ func resourceKubernetesStatefulSet() *schema.Resource { } func resourceKubernetesStatefulSetCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) spec, err := expandStatefulSetSpec(d.Get("spec").([]interface{})) if err != nil { @@ -69,7 +69,7 @@ func resourceKubernetesStatefulSetCreate(d *schema.ResourceData, meta interface{ } func resourceKubernetesStatefulSetExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { @@ -88,7 +88,7 @@ func resourceKubernetesStatefulSetExists(d *schema.ResourceData, meta interface{ } func resourceKubernetesStatefulSetRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) id := d.Id() namespace, name, err := idParts(id) @@ -124,7 +124,7 @@ func resourceKubernetesStatefulSetRead(d *schema.ResourceData, meta interface{}) } func resourceKubernetesStatefulSetUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { return fmt.Errorf("Error parsing resource ID: %#v", err) @@ -155,7 +155,7 @@ func resourceKubernetesStatefulSetUpdate(d *schema.ResourceData, meta interface{ } func resourceKubernetesStatefulSetDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) namespace, name, err := idParts(d.Id()) if err != nil { diff --git a/kubernetes/resource_kubernetes_storage_class.go b/kubernetes/resource_kubernetes_storage_class.go index 3330d6fe3d..9f21465b4c 100644 --- a/kubernetes/resource_kubernetes_storage_class.go +++ b/kubernetes/resource_kubernetes_storage_class.go @@ -55,7 +55,7 @@ func resourceKubernetesStorageClass() *schema.Resource { } func resourceKubernetesStorageClassCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) metadata := expandMetadata(d.Get("metadata").([]interface{})) reclaimPolicy := v1.PersistentVolumeReclaimPolicy(d.Get("reclaim_policy").(string)) @@ -83,7 +83,7 @@ func resourceKubernetesStorageClassCreate(d *schema.ResourceData, meta interface } func resourceKubernetesStorageClassRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Reading storage class %s", name) @@ -106,7 +106,7 @@ func resourceKubernetesStorageClassRead(d *schema.ResourceData, meta interface{} } func resourceKubernetesStorageClassUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() ops := patchMetadata("metadata.0.", "/metadata/", d) @@ -126,7 +126,7 @@ func resourceKubernetesStorageClassUpdate(d *schema.ResourceData, meta interface } func resourceKubernetesStorageClassDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Deleting storage class: %#v", name) @@ -142,7 +142,7 @@ func resourceKubernetesStorageClassDelete(d *schema.ResourceData, meta interface } func resourceKubernetesStorageClassExists(d *schema.ResourceData, meta interface{}) (bool, error) { - conn := meta.(*kubernetes.Clientset) + conn := meta.(kubernetes.Interface) name := d.Id() log.Printf("[INFO] Checking storage class %s", name) diff --git a/vendor/github.com/ghodss/yaml/LICENSE b/vendor/github.com/ghodss/yaml/LICENSE new file mode 100644 index 0000000000..7805d36de7 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/LICENSE @@ -0,0 +1,50 @@ +The MIT License (MIT) + +Copyright (c) 2014 Sam Ghods + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/ghodss/yaml/README.md b/vendor/github.com/ghodss/yaml/README.md new file mode 100644 index 0000000000..0200f75b4d --- /dev/null +++ b/vendor/github.com/ghodss/yaml/README.md @@ -0,0 +1,121 @@ +# YAML marshaling and unmarshaling support for Go + +[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml) + +## Introduction + +A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs. + +In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). + +## Compatibility + +This package uses [go-yaml](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility). + +## Caveats + +**Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example: + +``` +BAD: + exampleKey: !!binary gIGC + +GOOD: + exampleKey: gIGC +... and decode the base64 data in your code. +``` + +**Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys. + +## Installation and usage + +To install, run: + +``` +$ go get github.com/ghodss/yaml +``` + +And import using: + +``` +import "github.com/ghodss/yaml" +``` + +Usage is very similar to the JSON library: + +```go +package main + +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +type Person struct { + Name string `json:"name"` // Affects YAML field names too. + Age int `json:"age"` +} + +func main() { + // Marshal a Person struct to YAML. + p := Person{"John", 30} + y, err := yaml.Marshal(p) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + age: 30 + name: John + */ + + // Unmarshal the YAML back into a Person struct. + var p2 Person + err = yaml.Unmarshal(y, &p2) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(p2) + /* Output: + {John 30} + */ +} +``` + +`yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available: + +```go +package main + +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +func main() { + j := []byte(`{"name": "John", "age": 30}`) + y, err := yaml.JSONToYAML(j) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + name: John + age: 30 + */ + j2, err := yaml.YAMLToJSON(y) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(j2)) + /* Output: + {"age":30,"name":"John"} + */ +} +``` diff --git a/vendor/github.com/ghodss/yaml/fields.go b/vendor/github.com/ghodss/yaml/fields.go new file mode 100644 index 0000000000..5860074026 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/fields.go @@ -0,0 +1,501 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package yaml + +import ( + "bytes" + "encoding" + "encoding/json" + "reflect" + "sort" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// if it encounters an Unmarshaler, indirect stops and returns that. +// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. +func indirect(v reflect.Value, decodingNull bool) (json.Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { + v = e + continue + } + } + + if v.Kind() != reflect.Ptr { + break + } + + if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { + break + } + if v.IsNil() { + if v.CanSet() { + v.Set(reflect.New(v.Type().Elem())) + } else { + v = reflect.New(v.Type().Elem()) + } + } + if v.Type().NumMethod() > 0 { + if u, ok := v.Interface().(json.Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + v = v.Elem() + } + return nil, nil, v +} + +// A field represents a single field found in a struct. +type field struct { + name string + nameBytes []byte // []byte(name) + equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent + + tag bool + index []int + typ reflect.Type + omitEmpty bool + quoted bool +} + +func fillField(f field) field { + f.nameBytes = []byte(f.name) + f.equalFold = foldFunc(f.nameBytes) + return f +} + +// byName sorts field by name, breaking ties with depth, +// then breaking ties with "name came from json tag", then +// breaking ties with index sequence. +type byName []field + +func (x byName) Len() int { return len(x) } + +func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byName) Less(i, j int) bool { + if x[i].name != x[j].name { + return x[i].name < x[j].name + } + if len(x[i].index) != len(x[j].index) { + return len(x[i].index) < len(x[j].index) + } + if x[i].tag != x[j].tag { + return x[i].tag + } + return byIndex(x).Less(i, j) +} + +// byIndex sorts field by index sequence. +type byIndex []field + +func (x byIndex) Len() int { return len(x) } + +func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byIndex) Less(i, j int) bool { + for k, xik := range x[i].index { + if k >= len(x[j].index) { + return false + } + if xik != x[j].index[k] { + return xik < x[j].index[k] + } + } + return len(x[i].index) < len(x[j].index) +} + +// typeFields returns a list of fields that JSON should recognize for the given type. +// The algorithm is breadth-first search over the set of structs to include - the top struct +// and then any reachable anonymous structs. +func typeFields(t reflect.Type) []field { + // Anonymous fields to explore at the current level and the next. + current := []field{} + next := []field{{typ: t}} + + // Count of queued names for current level and the next. + count := map[reflect.Type]int{} + nextCount := map[reflect.Type]int{} + + // Types already visited at an earlier level. + visited := map[reflect.Type]bool{} + + // Fields found. + var fields []field + + for len(next) > 0 { + current, next = next, current[:0] + count, nextCount = nextCount, map[reflect.Type]int{} + + for _, f := range current { + if visited[f.typ] { + continue + } + visited[f.typ] = true + + // Scan f.typ for fields to include. + for i := 0; i < f.typ.NumField(); i++ { + sf := f.typ.Field(i) + if sf.PkgPath != "" { // unexported + continue + } + tag := sf.Tag.Get("json") + if tag == "-" { + continue + } + name, opts := parseTag(tag) + if !isValidTag(name) { + name = "" + } + index := make([]int, len(f.index)+1) + copy(index, f.index) + index[len(f.index)] = i + + ft := sf.Type + if ft.Name() == "" && ft.Kind() == reflect.Ptr { + // Follow pointer. + ft = ft.Elem() + } + + // Record found field and index sequence. + if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { + tagged := name != "" + if name == "" { + name = sf.Name + } + fields = append(fields, fillField(field{ + name: name, + tag: tagged, + index: index, + typ: ft, + omitEmpty: opts.Contains("omitempty"), + quoted: opts.Contains("string"), + })) + if count[f.typ] > 1 { + // If there were multiple instances, add a second, + // so that the annihilation code will see a duplicate. + // It only cares about the distinction between 1 or 2, + // so don't bother generating any more copies. + fields = append(fields, fields[len(fields)-1]) + } + continue + } + + // Record new anonymous struct to explore in next round. + nextCount[ft]++ + if nextCount[ft] == 1 { + next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft})) + } + } + } + } + + sort.Sort(byName(fields)) + + // Delete all fields that are hidden by the Go rules for embedded fields, + // except that fields with JSON tags are promoted. + + // The fields are sorted in primary order of name, secondary order + // of field index length. Loop over names; for each name, delete + // hidden fields by choosing the one dominant field that survives. + out := fields[:0] + for advance, i := 0, 0; i < len(fields); i += advance { + // One iteration per name. + // Find the sequence of fields with the name of this first field. + fi := fields[i] + name := fi.name + for advance = 1; i+advance < len(fields); advance++ { + fj := fields[i+advance] + if fj.name != name { + break + } + } + if advance == 1 { // Only one field with this name + out = append(out, fi) + continue + } + dominant, ok := dominantField(fields[i : i+advance]) + if ok { + out = append(out, dominant) + } + } + + fields = out + sort.Sort(byIndex(fields)) + + return fields +} + +// dominantField looks through the fields, all of which are known to +// have the same name, to find the single field that dominates the +// others using Go's embedding rules, modified by the presence of +// JSON tags. If there are multiple top-level fields, the boolean +// will be false: This condition is an error in Go and we skip all +// the fields. +func dominantField(fields []field) (field, bool) { + // The fields are sorted in increasing index-length order. The winner + // must therefore be one with the shortest index length. Drop all + // longer entries, which is easy: just truncate the slice. + length := len(fields[0].index) + tagged := -1 // Index of first tagged field. + for i, f := range fields { + if len(f.index) > length { + fields = fields[:i] + break + } + if f.tag { + if tagged >= 0 { + // Multiple tagged fields at the same level: conflict. + // Return no field. + return field{}, false + } + tagged = i + } + } + if tagged >= 0 { + return fields[tagged], true + } + // All remaining fields have the same length. If there's more than one, + // we have a conflict (two fields named "X" at the same level) and we + // return no field. + if len(fields) > 1 { + return field{}, false + } + return fields[0], true +} + +var fieldCache struct { + sync.RWMutex + m map[reflect.Type][]field +} + +// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. +func cachedTypeFields(t reflect.Type) []field { + fieldCache.RLock() + f := fieldCache.m[t] + fieldCache.RUnlock() + if f != nil { + return f + } + + // Compute fields without lock. + // Might duplicate effort but won't hold other computations back. + f = typeFields(t) + if f == nil { + f = []field{} + } + + fieldCache.Lock() + if fieldCache.m == nil { + fieldCache.m = map[reflect.Type][]field{} + } + fieldCache.m[t] = f + fieldCache.Unlock() + return f +} + +func isValidTag(s string) bool { + if s == "" { + return false + } + for _, c := range s { + switch { + case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): + // Backslash and quote chars are reserved, but + // otherwise any punctuation chars are allowed + // in a tag name. + default: + if !unicode.IsLetter(c) && !unicode.IsDigit(c) { + return false + } + } + } + return true +} + +const ( + caseMask = ^byte(0x20) // Mask to ignore case in ASCII. + kelvin = '\u212a' + smallLongEss = '\u017f' +) + +// foldFunc returns one of four different case folding equivalence +// functions, from most general (and slow) to fastest: +// +// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 +// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') +// 3) asciiEqualFold, no special, but includes non-letters (including _) +// 4) simpleLetterEqualFold, no specials, no non-letters. +// +// The letters S and K are special because they map to 3 runes, not just 2: +// * S maps to s and to U+017F 'ſ' Latin small letter long s +// * k maps to K and to U+212A 'K' Kelvin sign +// See http://play.golang.org/p/tTxjOc0OGo +// +// The returned function is specialized for matching against s and +// should only be given s. It's not curried for performance reasons. +func foldFunc(s []byte) func(s, t []byte) bool { + nonLetter := false + special := false // special letter + for _, b := range s { + if b >= utf8.RuneSelf { + return bytes.EqualFold + } + upper := b & caseMask + if upper < 'A' || upper > 'Z' { + nonLetter = true + } else if upper == 'K' || upper == 'S' { + // See above for why these letters are special. + special = true + } + } + if special { + return equalFoldRight + } + if nonLetter { + return asciiEqualFold + } + return simpleLetterEqualFold +} + +// equalFoldRight is a specialization of bytes.EqualFold when s is +// known to be all ASCII (including punctuation), but contains an 's', +// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. +// See comments on foldFunc. +func equalFoldRight(s, t []byte) bool { + for _, sb := range s { + if len(t) == 0 { + return false + } + tb := t[0] + if tb < utf8.RuneSelf { + if sb != tb { + sbUpper := sb & caseMask + if 'A' <= sbUpper && sbUpper <= 'Z' { + if sbUpper != tb&caseMask { + return false + } + } else { + return false + } + } + t = t[1:] + continue + } + // sb is ASCII and t is not. t must be either kelvin + // sign or long s; sb must be s, S, k, or K. + tr, size := utf8.DecodeRune(t) + switch sb { + case 's', 'S': + if tr != smallLongEss { + return false + } + case 'k', 'K': + if tr != kelvin { + return false + } + default: + return false + } + t = t[size:] + + } + if len(t) > 0 { + return false + } + return true +} + +// asciiEqualFold is a specialization of bytes.EqualFold for use when +// s is all ASCII (but may contain non-letters) and contains no +// special-folding letters. +// See comments on foldFunc. +func asciiEqualFold(s, t []byte) bool { + if len(s) != len(t) { + return false + } + for i, sb := range s { + tb := t[i] + if sb == tb { + continue + } + if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { + if sb&caseMask != tb&caseMask { + return false + } + } else { + return false + } + } + return true +} + +// simpleLetterEqualFold is a specialization of bytes.EqualFold for +// use when s is all ASCII letters (no underscores, etc) and also +// doesn't contain 'k', 'K', 's', or 'S'. +// See comments on foldFunc. +func simpleLetterEqualFold(s, t []byte) bool { + if len(s) != len(t) { + return false + } + for i, b := range s { + if b&caseMask != t[i]&caseMask { + return false + } + } + return true +} + +// tagOptions is the string following a comma in a struct field's "json" +// tag, or the empty string. It does not include the leading comma. +type tagOptions string + +// parseTag splits a struct field's json tag into its name and +// comma-separated options. +func parseTag(tag string) (string, tagOptions) { + if idx := strings.Index(tag, ","); idx != -1 { + return tag[:idx], tagOptions(tag[idx+1:]) + } + return tag, tagOptions("") +} + +// Contains reports whether a comma-separated list of options +// contains a particular substr flag. substr must be surrounded by a +// string boundary or commas. +func (o tagOptions) Contains(optionName string) bool { + if len(o) == 0 { + return false + } + s := string(o) + for s != "" { + var next string + i := strings.Index(s, ",") + if i >= 0 { + s, next = s[:i], s[i+1:] + } + if s == optionName { + return true + } + s = next + } + return false +} diff --git a/vendor/github.com/ghodss/yaml/yaml.go b/vendor/github.com/ghodss/yaml/yaml.go new file mode 100644 index 0000000000..6e7f14fc7f --- /dev/null +++ b/vendor/github.com/ghodss/yaml/yaml.go @@ -0,0 +1,305 @@ +package yaml + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "reflect" + "strconv" + + "gopkg.in/yaml.v2" +) + +// Marshals the object into JSON then converts JSON to YAML and returns the +// YAML. +func Marshal(o interface{}) ([]byte, error) { + j, err := json.Marshal(o) + if err != nil { + return nil, fmt.Errorf("error marshaling into JSON: %v", err) + } + + y, err := JSONToYAML(j) + if err != nil { + return nil, fmt.Errorf("error converting JSON to YAML: %v", err) + } + + return y, nil +} + +// JSONOpt is a decoding option for decoding from JSON format. +type JSONOpt func(*json.Decoder) *json.Decoder + +// Unmarshal converts YAML to JSON then uses JSON to unmarshal into an object, +// optionally configuring the behavior of the JSON unmarshal. +func Unmarshal(y []byte, o interface{}, opts ...JSONOpt) error { + vo := reflect.ValueOf(o) + j, err := yamlToJSON(y, &vo, yaml.Unmarshal) + if err != nil { + return fmt.Errorf("error converting YAML to JSON: %v", err) + } + + err = jsonUnmarshal(bytes.NewReader(j), o, opts...) + if err != nil { + return fmt.Errorf("error unmarshaling JSON: %v", err) + } + + return nil +} + +// jsonUnmarshal unmarshals the JSON byte stream from the given reader into the +// object, optionally applying decoder options prior to decoding. We are not +// using json.Unmarshal directly as we want the chance to pass in non-default +// options. +func jsonUnmarshal(r io.Reader, o interface{}, opts ...JSONOpt) error { + d := json.NewDecoder(r) + for _, opt := range opts { + d = opt(d) + } + if err := d.Decode(&o); err != nil { + return fmt.Errorf("while decoding JSON: %v", err) + } + return nil +} + +// Convert JSON to YAML. +func JSONToYAML(j []byte) ([]byte, error) { + // Convert the JSON to an object. + var jsonObj interface{} + // We are using yaml.Unmarshal here (instead of json.Unmarshal) because the + // Go JSON library doesn't try to pick the right number type (int, float, + // etc.) when unmarshalling to interface{}, it just picks float64 + // universally. go-yaml does go through the effort of picking the right + // number type, so we can preserve number type throughout this process. + err := yaml.Unmarshal(j, &jsonObj) + if err != nil { + return nil, err + } + + // Marshal this object into YAML. + return yaml.Marshal(jsonObj) +} + +// YAMLToJSON converts YAML to JSON. Since JSON is a subset of YAML, +// passing JSON through this method should be a no-op. +// +// Things YAML can do that are not supported by JSON: +// * In YAML you can have binary and null keys in your maps. These are invalid +// in JSON. (int and float keys are converted to strings.) +// * Binary data in YAML with the !!binary tag is not supported. If you want to +// use binary data with this library, encode the data as base64 as usual but do +// not use the !!binary tag in your YAML. This will ensure the original base64 +// encoded data makes it all the way through to the JSON. +// +// For strict decoding of YAML, use YAMLToJSONStrict. +func YAMLToJSON(y []byte) ([]byte, error) { + return yamlToJSON(y, nil, yaml.Unmarshal) +} + +// YAMLToJSONStrict is like YAMLToJSON but enables strict YAML decoding, +// returning an error on any duplicate field names. +func YAMLToJSONStrict(y []byte) ([]byte, error) { + return yamlToJSON(y, nil, yaml.UnmarshalStrict) +} + +func yamlToJSON(y []byte, jsonTarget *reflect.Value, yamlUnmarshal func([]byte, interface{}) error) ([]byte, error) { + // Convert the YAML to an object. + var yamlObj interface{} + err := yamlUnmarshal(y, &yamlObj) + if err != nil { + return nil, err + } + + // YAML objects are not completely compatible with JSON objects (e.g. you + // can have non-string keys in YAML). So, convert the YAML-compatible object + // to a JSON-compatible object, failing with an error if irrecoverable + // incompatibilties happen along the way. + jsonObj, err := convertToJSONableObject(yamlObj, jsonTarget) + if err != nil { + return nil, err + } + + // Convert this object to JSON and return the data. + return json.Marshal(jsonObj) +} + +func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (interface{}, error) { + var err error + + // Resolve jsonTarget to a concrete value (i.e. not a pointer or an + // interface). We pass decodingNull as false because we're not actually + // decoding into the value, we're just checking if the ultimate target is a + // string. + if jsonTarget != nil { + ju, tu, pv := indirect(*jsonTarget, false) + // We have a JSON or Text Umarshaler at this level, so we can't be trying + // to decode into a string. + if ju != nil || tu != nil { + jsonTarget = nil + } else { + jsonTarget = &pv + } + } + + // If yamlObj is a number or a boolean, check if jsonTarget is a string - + // if so, coerce. Else return normal. + // If yamlObj is a map or array, find the field that each key is + // unmarshaling to, and when you recurse pass the reflect.Value for that + // field back into this function. + switch typedYAMLObj := yamlObj.(type) { + case map[interface{}]interface{}: + // JSON does not support arbitrary keys in a map, so we must convert + // these keys to strings. + // + // From my reading of go-yaml v2 (specifically the resolve function), + // keys can only have the types string, int, int64, float64, binary + // (unsupported), or null (unsupported). + strMap := make(map[string]interface{}) + for k, v := range typedYAMLObj { + // Resolve the key to a string first. + var keyString string + switch typedKey := k.(type) { + case string: + keyString = typedKey + case int: + keyString = strconv.Itoa(typedKey) + case int64: + // go-yaml will only return an int64 as a key if the system + // architecture is 32-bit and the key's value is between 32-bit + // and 64-bit. Otherwise the key type will simply be int. + keyString = strconv.FormatInt(typedKey, 10) + case float64: + // Stolen from go-yaml to use the same conversion to string as + // the go-yaml library uses to convert float to string when + // Marshaling. + s := strconv.FormatFloat(typedKey, 'g', -1, 32) + switch s { + case "+Inf": + s = ".inf" + case "-Inf": + s = "-.inf" + case "NaN": + s = ".nan" + } + keyString = s + case bool: + if typedKey { + keyString = "true" + } else { + keyString = "false" + } + default: + return nil, fmt.Errorf("Unsupported map key of type: %s, key: %+#v, value: %+#v", + reflect.TypeOf(k), k, v) + } + + // jsonTarget should be a struct or a map. If it's a struct, find + // the field it's going to map to and pass its reflect.Value. If + // it's a map, find the element type of the map and pass the + // reflect.Value created from that type. If it's neither, just pass + // nil - JSON conversion will error for us if it's a real issue. + if jsonTarget != nil { + t := *jsonTarget + if t.Kind() == reflect.Struct { + keyBytes := []byte(keyString) + // Find the field that the JSON library would use. + var f *field + fields := cachedTypeFields(t.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, keyBytes) { + f = ff + break + } + // Do case-insensitive comparison. + if f == nil && ff.equalFold(ff.nameBytes, keyBytes) { + f = ff + } + } + if f != nil { + // Find the reflect.Value of the most preferential + // struct field. + jtf := t.Field(f.index[0]) + strMap[keyString], err = convertToJSONableObject(v, &jtf) + if err != nil { + return nil, err + } + continue + } + } else if t.Kind() == reflect.Map { + // Create a zero value of the map's element type to use as + // the JSON target. + jtv := reflect.Zero(t.Type().Elem()) + strMap[keyString], err = convertToJSONableObject(v, &jtv) + if err != nil { + return nil, err + } + continue + } + } + strMap[keyString], err = convertToJSONableObject(v, nil) + if err != nil { + return nil, err + } + } + return strMap, nil + case []interface{}: + // We need to recurse into arrays in case there are any + // map[interface{}]interface{}'s inside and to convert any + // numbers to strings. + + // If jsonTarget is a slice (which it really should be), find the + // thing it's going to map to. If it's not a slice, just pass nil + // - JSON conversion will error for us if it's a real issue. + var jsonSliceElemValue *reflect.Value + if jsonTarget != nil { + t := *jsonTarget + if t.Kind() == reflect.Slice { + // By default slices point to nil, but we need a reflect.Value + // pointing to a value of the slice type, so we create one here. + ev := reflect.Indirect(reflect.New(t.Type().Elem())) + jsonSliceElemValue = &ev + } + } + + // Make and use a new array. + arr := make([]interface{}, len(typedYAMLObj)) + for i, v := range typedYAMLObj { + arr[i], err = convertToJSONableObject(v, jsonSliceElemValue) + if err != nil { + return nil, err + } + } + return arr, nil + default: + // If the target type is a string and the YAML type is a number, + // convert the YAML type to a string. + if jsonTarget != nil && (*jsonTarget).Kind() == reflect.String { + // Based on my reading of go-yaml, it may return int, int64, + // float64, or uint64. + var s string + switch typedVal := typedYAMLObj.(type) { + case int: + s = strconv.FormatInt(int64(typedVal), 10) + case int64: + s = strconv.FormatInt(typedVal, 10) + case float64: + s = strconv.FormatFloat(typedVal, 'g', -1, 32) + case uint64: + s = strconv.FormatUint(typedVal, 10) + case bool: + if typedVal { + s = "true" + } else { + s = "false" + } + } + if len(s) > 0 { + yamlObj = interface{}(s) + } + } + return yamlObj, nil + } + + return nil, nil +} diff --git a/vendor/github.com/ghodss/yaml/yaml_go110.go b/vendor/github.com/ghodss/yaml/yaml_go110.go new file mode 100644 index 0000000000..ab3e06a222 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/yaml_go110.go @@ -0,0 +1,14 @@ +// This file contains changes that are only compatible with go 1.10 and onwards. + +// +build go1.10 + +package yaml + +import "encoding/json" + +// DisallowUnknownFields configures the JSON decoder to error out if unknown +// fields come along, instead of dropping them by default. +func DisallowUnknownFields(d *json.Decoder) *json.Decoder { + d.DisallowUnknownFields() + return d +} diff --git a/vendor/github.com/ghodss/yaml/yaml_go110_test.go b/vendor/github.com/ghodss/yaml/yaml_go110_test.go new file mode 100644 index 0000000000..b7767b7c4f --- /dev/null +++ b/vendor/github.com/ghodss/yaml/yaml_go110_test.go @@ -0,0 +1,46 @@ +// +build go1.10 + +package yaml + +import ( + "fmt" + "testing" +) + +func TestUnmarshalWithTags(t *testing.T) { + type WithTaggedField struct { + Field string `json:"field"` + } + + t.Run("Known tagged field", func(t *testing.T) { + y := []byte(`field: "hello"`) + v := WithTaggedField{} + if err := Unmarshal(y, &v, DisallowUnknownFields); err != nil { + t.Errorf("unexpected error: %v", err) + } + if v.Field != "hello" { + t.Errorf("v.Field=%v, want 'hello'", v.Field) + } + + }) + t.Run("With unknown tagged field", func(t *testing.T) { + y := []byte(`unknown: "hello"`) + v := WithTaggedField{} + err := Unmarshal(y, &v, DisallowUnknownFields) + if err == nil { + t.Errorf("want error because of unknown field, got : v=%#v", v) + } + }) + +} + +func ExampleUnknown() { + type WithTaggedField struct { + Field string `json:"field"` + } + y := []byte(`unknown: "hello"`) + v := WithTaggedField{} + fmt.Printf("%v\n", Unmarshal(y, &v, DisallowUnknownFields)) + // Ouptut: + // unmarshaling JSON: while decoding JSON: json: unknown field "unknown" +} diff --git a/vendor/github.com/ghodss/yaml/yaml_test.go b/vendor/github.com/ghodss/yaml/yaml_test.go new file mode 100644 index 0000000000..9250cf242a --- /dev/null +++ b/vendor/github.com/ghodss/yaml/yaml_test.go @@ -0,0 +1,300 @@ +package yaml + +import ( + "fmt" + "math" + "reflect" + "strconv" + "testing" +) + +type MarshalTest struct { + A string + B int64 + // Would like to test float64, but it's not supported in go-yaml. + // (See https://github.com/go-yaml/yaml/issues/83.) + C float32 +} + +func TestMarshal(t *testing.T) { + f32String := strconv.FormatFloat(math.MaxFloat32, 'g', -1, 32) + s := MarshalTest{"a", math.MaxInt64, math.MaxFloat32} + e := []byte(fmt.Sprintf("A: a\nB: %d\nC: %s\n", math.MaxInt64, f32String)) + + y, err := Marshal(s) + if err != nil { + t.Errorf("error marshaling YAML: %v", err) + } + + if !reflect.DeepEqual(y, e) { + t.Errorf("marshal YAML was unsuccessful, expected: %#v, got: %#v", + string(e), string(y)) + } +} + +type UnmarshalString struct { + A string + True string +} + +type UnmarshalStringMap struct { + A map[string]string +} + +type UnmarshalNestedString struct { + A NestedString +} + +type NestedString struct { + A string +} + +type UnmarshalSlice struct { + A []NestedSlice +} + +type NestedSlice struct { + B string + C *string +} + +func TestUnmarshal(t *testing.T) { + y := []byte("a: 1") + s1 := UnmarshalString{} + e1 := UnmarshalString{A: "1"} + unmarshal(t, y, &s1, &e1) + + y = []byte("a: true") + s1 = UnmarshalString{} + e1 = UnmarshalString{A: "true"} + unmarshal(t, y, &s1, &e1) + + y = []byte("true: 1") + s1 = UnmarshalString{} + e1 = UnmarshalString{True: "1"} + unmarshal(t, y, &s1, &e1) + + y = []byte("a:\n a: 1") + s2 := UnmarshalNestedString{} + e2 := UnmarshalNestedString{NestedString{"1"}} + unmarshal(t, y, &s2, &e2) + + y = []byte("a:\n - b: abc\n c: def\n - b: 123\n c: 456\n") + s3 := UnmarshalSlice{} + e3 := UnmarshalSlice{[]NestedSlice{NestedSlice{"abc", strPtr("def")}, NestedSlice{"123", strPtr("456")}}} + unmarshal(t, y, &s3, &e3) + + y = []byte("a:\n b: 1") + s4 := UnmarshalStringMap{} + e4 := UnmarshalStringMap{map[string]string{"b": "1"}} + unmarshal(t, y, &s4, &e4) + + y = []byte(` +a: + name: TestA +b: + name: TestB +`) + type NamedThing struct { + Name string `json:"name"` + } + s5 := map[string]*NamedThing{} + e5 := map[string]*NamedThing{ + "a": &NamedThing{Name: "TestA"}, + "b": &NamedThing{Name: "TestB"}, + } + unmarshal(t, y, &s5, &e5) +} + +func unmarshal(t *testing.T, y []byte, s, e interface{}, opts ...JSONOpt) { + err := Unmarshal(y, s, opts...) + if err != nil { + t.Errorf("error unmarshaling YAML: %v", err) + } + + if !reflect.DeepEqual(s, e) { + t.Errorf("unmarshal YAML was unsuccessful, expected: %+#v, got: %+#v", + e, s) + } +} + +type Case struct { + input string + output string + // By default we test that reversing the output == input. But if there is a + // difference in the reversed output, you can optionally specify it here. + reverse *string +} + +type RunType int + +const ( + RunTypeJSONToYAML RunType = iota + RunTypeYAMLToJSON +) + +func TestJSONToYAML(t *testing.T) { + cases := []Case{ + { + `{"t":"a"}`, + "t: a\n", + nil, + }, { + `{"t":null}`, + "t: null\n", + nil, + }, + } + + runCases(t, RunTypeJSONToYAML, cases) +} + +func TestYAMLToJSON(t *testing.T) { + cases := []Case{ + { + "t: a\n", + `{"t":"a"}`, + nil, + }, { + "t: \n", + `{"t":null}`, + strPtr("t: null\n"), + }, { + "t: null\n", + `{"t":null}`, + nil, + }, { + "1: a\n", + `{"1":"a"}`, + strPtr("\"1\": a\n"), + }, { + "1000000000000000000000000000000000000: a\n", + `{"1e+36":"a"}`, + strPtr("\"1e+36\": a\n"), + }, { + "1e+36: a\n", + `{"1e+36":"a"}`, + strPtr("\"1e+36\": a\n"), + }, { + "\"1e+36\": a\n", + `{"1e+36":"a"}`, + nil, + }, { + "\"1.2\": a\n", + `{"1.2":"a"}`, + nil, + }, { + "- t: a\n", + `[{"t":"a"}]`, + nil, + }, { + "- t: a\n" + + "- t:\n" + + " b: 1\n" + + " c: 2\n", + `[{"t":"a"},{"t":{"b":1,"c":2}}]`, + nil, + }, { + `[{t: a}, {t: {b: 1, c: 2}}]`, + `[{"t":"a"},{"t":{"b":1,"c":2}}]`, + strPtr("- t: a\n" + + "- t:\n" + + " b: 1\n" + + " c: 2\n"), + }, { + "- t: \n", + `[{"t":null}]`, + strPtr("- t: null\n"), + }, { + "- t: null\n", + `[{"t":null}]`, + nil, + }, + } + + // Cases that should produce errors. + _ = []Case{ + { + "~: a", + `{"null":"a"}`, + nil, + }, { + "a: !!binary gIGC\n", + "{\"a\":\"\x80\x81\x82\"}", + nil, + }, + } + + runCases(t, RunTypeYAMLToJSON, cases) +} + +func runCases(t *testing.T, runType RunType, cases []Case) { + var f func([]byte) ([]byte, error) + var invF func([]byte) ([]byte, error) + var msg string + var invMsg string + if runType == RunTypeJSONToYAML { + f = JSONToYAML + invF = YAMLToJSON + msg = "JSON to YAML" + invMsg = "YAML back to JSON" + } else { + f = YAMLToJSON + invF = JSONToYAML + msg = "YAML to JSON" + invMsg = "JSON back to YAML" + } + + for _, c := range cases { + // Convert the string. + t.Logf("converting %s\n", c.input) + output, err := f([]byte(c.input)) + if err != nil { + t.Errorf("Failed to convert %s, input: `%s`, err: %v", msg, c.input, err) + } + + // Check it against the expected output. + if string(output) != c.output { + t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`", + msg, c.input, c.output, string(output)) + } + + // Set the string that we will compare the reversed output to. + reverse := c.input + // If a special reverse string was specified, use that instead. + if c.reverse != nil { + reverse = *c.reverse + } + + // Reverse the output. + input, err := invF(output) + if err != nil { + t.Errorf("Failed to convert %s, input: `%s`, err: %v", invMsg, string(output), err) + } + + // Check the reverse is equal to the input (or to *c.reverse). + if string(input) != reverse { + t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`", + invMsg, string(output), reverse, string(input)) + } + } + +} + +// To be able to easily fill in the *Case.reverse string above. +func strPtr(s string) *string { + return &s +} + +func TestYAMLToJSONStrict(t *testing.T) { + const data = ` +foo: bar +foo: baz +` + if _, err := YAMLToJSON([]byte(data)); err != nil { + t.Error("expected YAMLtoJSON to pass on duplicate field names") + } + if _, err := YAMLToJSONStrict([]byte(data)); err == nil { + t.Error("expected YAMLtoJSONStrict to fail on duplicate field names") + } +} diff --git a/vendor/vendor.json b/vendor/vendor.json new file mode 100644 index 0000000000..52fb73e538 --- /dev/null +++ b/vendor/vendor.json @@ -0,0 +1,13 @@ +{ + "comment": "", + "ignore": "", + "package": [ + { + "checksumSHA1": "//MRaQwvODFsKuAfSqPV+tfyY+0=", + "path": "github.com/ghodss/yaml", + "revision": "c7ce16629ff4cd059ed96ed06419dd3856fd3577", + "revisionTime": "2018-08-20T08:47:58Z" + } + ], + "rootPath": "github.com/terraform-providers/terraform-provider-kubernetes" +}