func (cl *Client) Create(config model.Config) (string, error) {
	schema, exists := cl.descriptor.GetByType(config.Type)
	if !exists {
		return "", fmt.Errorf("unrecognized type %q", config.Type)
	}
	if err := schema.Validate(config.Spec); err != nil {
		return "", multierror.Prefix(err, "validation error:")
	}
	out, err := ConvertConfig(schema, config)
	if err != nil {
		return "", err
	}
	obj := knownTypes[schema.Type].object.DeepCopyObject().(IstioObject)
	err = cl.dynamic.Post().
		Namespace(out.GetObjectMeta().Namespace).
		Resource(ResourceName(schema.Plural)).
		Body(out).
		Do().Into(obj)
	if err != nil {
		return "", err
	}
	return obj.GetObjectMeta().ResourceVersion, nil
}
Create implements store interface
package crd
import (
	"fmt"
	"time"
	"github.com/golang/glog"
	multierror "github.com/hashicorp/go-multierror"
	apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/util/wait"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"istio.io/pilot/model"
	"istio.io/pilot/platform/kube"
)
var IstioAPIGroupVersion = schema.GroupVersion{
	Group:   model.IstioAPIGroup,
	Version: model.IstioAPIVersion,
}
type IstioObject interface {
	runtime.Object
	GetSpec() map[string]interface{}
	SetSpec(map[string]interface{})
	GetObjectMeta() meta_v1.ObjectMeta
	SetObjectMeta(meta_v1.ObjectMeta)
}
type IstioObjectList interface {
	runtime.Object
	GetItems() []IstioObject
}
type Client struct {
	descriptor model.ConfigDescriptor
	restconfig *rest.Config
	dynamic *rest.RESTClient
	domainSuffix string
}
func CreateRESTConfig(kubeconfig string) (config *rest.Config, err error) {
	if kubeconfig == "" {
		config, err = rest.InClusterConfig()
	} else {
		config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
	}
	if err != nil {
		return
	}
	config.GroupVersion = &IstioAPIGroupVersion
	config.APIPath = "/apis"
	config.ContentType = runtime.ContentTypeJSON
	types := runtime.NewScheme()
	schemeBuilder := runtime.NewSchemeBuilder(
		func(scheme *runtime.Scheme) error {
			for _, kind := range knownTypes {
				scheme.AddKnownTypes(IstioAPIGroupVersion, kind.object, kind.collection)
			}
			meta_v1.AddToGroupVersion(scheme, IstioAPIGroupVersion)
			return nil
		})
	err = schemeBuilder.AddToScheme(types)
	config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(types)}
	return
}
func NewClient(config string, descriptor model.ConfigDescriptor, domainSuffix string) (*Client, error) {
	for _, typ := range descriptor {
		if _, exists := knownTypes[typ.Type]; !exists {
			return nil, fmt.Errorf("missing known type for %q", typ.Type)
		}
	}
	kubeconfig, err := kube.ResolveConfig(config)
	if err != nil {
		return nil, err
	}
	restconfig, err := CreateRESTConfig(kubeconfig)
	if err != nil {
		return nil, err
	}
	dynamic, err := rest.RESTClientFor(restconfig)
	if err != nil {
		return nil, err
	}
	out := &Client{
		descriptor:   descriptor,
		restconfig:   restconfig,
		dynamic:      dynamic,
		domainSuffix: domainSuffix,
	}
	return out, nil
}
func (cl *Client) RegisterResources() error {
	clientset, err := apiextensionsclient.NewForConfig(cl.restconfig)
	if err != nil {
		return err
	}
	for _, schema := range cl.descriptor {
		name := ResourceName(schema.Plural) + "." + model.IstioAPIGroup
		crd := &apiextensionsv1beta1.CustomResourceDefinition{
			ObjectMeta: meta_v1.ObjectMeta{
				Name: name,
			},
			Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
				Group:   model.IstioAPIGroup,
				Version: model.IstioAPIVersion,
				Scope:   apiextensionsv1beta1.NamespaceScoped,
				Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
					Plural: ResourceName(schema.Plural),
					Kind:   KabobCaseToCamelCase(schema.Type),
				},
			},
		}
		glog.V(2).Infof("registering CRD %q", name)
		_, err = clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)
		if err != nil && !apierrors.IsAlreadyExists(err) {
			return err
		}
	}
	errPoll := wait.Poll(500*time.Millisecond, 60*time.Second, func() (bool, error) {
	descriptor:
		for _, schema := range cl.descriptor {
			name := ResourceName(schema.Plural) + "." + model.IstioAPIGroup
			crd, errGet := clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Get(name, meta_v1.GetOptions{})
			if errGet != nil {
				return false, errGet
			}
			for _, cond := range crd.Status.Conditions {
				switch cond.Type {
				case apiextensionsv1beta1.Established:
					if cond.Status == apiextensionsv1beta1.ConditionTrue {
						glog.V(2).Infof("established CRD %q", name)
						continue descriptor
					}
				case apiextensionsv1beta1.NamesAccepted:
					if cond.Status == apiextensionsv1beta1.ConditionFalse {
						glog.Warningf("name conflict: %v", cond.Reason)
					}
				}
			}
			glog.V(2).Infof("missing status condition for %q", name)
			return false, nil
		}
		return true, nil
	})
	if errPoll != nil {
		deleteErr := cl.DeregisterResources()
		if deleteErr != nil {
			return multierror.Append(errPoll, deleteErr)
		}
		return errPoll
	}
	return nil
}
func (cl *Client) DeregisterResources() error {
	clientset, err := apiextensionsclient.NewForConfig(cl.restconfig)
	if err != nil {
		return err
	}
	var errs error
	for _, schema := range cl.descriptor {
		name := ResourceName(schema.Plural) + "." + model.IstioAPIGroup
		err := clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Delete(name, nil)
		errs = multierror.Append(errs, err)
	}
	return errs
}
func (cl *Client) ConfigDescriptor() model.ConfigDescriptor {
	return cl.descriptor
}
func (cl *Client) Get(typ, name, namespace string) (*model.Config, bool) {
	schema, exists := cl.descriptor.GetByType(typ)
	if !exists {
		return nil, false
	}
	config := knownTypes[typ].object.DeepCopyObject().(IstioObject)
	err := cl.dynamic.Get().
		Namespace(namespace).
		Resource(ResourceName(schema.Plural)).
		Name(name).
		Do().Into(config)
	if err != nil {
		glog.Warning(err)
		return nil, false
	}
	out, err := ConvertObject(schema, config, cl.domainSuffix)
	if err != nil {
		glog.Warning(err)
		return nil, false
	}
	return out, true
}