mirror of
https://github.com/rancher/norman.git
synced 2025-09-03 08:14:40 +00:00
Generate clients in clientset style
This commit is contained in:
@@ -25,24 +25,14 @@ type ObjectClient struct {
|
||||
Factory ObjectFactory
|
||||
}
|
||||
|
||||
func NewObjectClient(namespace string, config rest.Config, apiResource *metav1.APIResource, gvk schema.GroupVersionKind, factory ObjectFactory) (*ObjectClient, error) {
|
||||
if config.NegotiatedSerializer == nil {
|
||||
configConfig := dynamic.ContentConfig()
|
||||
config.NegotiatedSerializer = configConfig.NegotiatedSerializer
|
||||
}
|
||||
|
||||
restClient, err := rest.UnversionedRESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func NewObjectClient(namespace string, restClient rest.Interface, apiResource *metav1.APIResource, gvk schema.GroupVersionKind, factory ObjectFactory) *ObjectClient {
|
||||
return &ObjectClient{
|
||||
restClient: restClient,
|
||||
resource: apiResource,
|
||||
gvk: gvk,
|
||||
ns: namespace,
|
||||
Factory: factory,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Create(o runtime.Object) (runtime.Object, error) {
|
||||
|
@@ -37,7 +37,7 @@ type genericController struct {
|
||||
running bool
|
||||
}
|
||||
|
||||
func NewGenericController(name string, objectClient *clientbase.ObjectClient) (GenericController, error) {
|
||||
func NewGenericController(name string, objectClient *clientbase.ObjectClient) GenericController {
|
||||
informer := cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: objectClient.List,
|
||||
@@ -50,7 +50,7 @@ func NewGenericController(name string, objectClient *clientbase.ObjectClient) (G
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(),
|
||||
name),
|
||||
name: name,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genericController) Informer() cache.SharedIndexInformer {
|
||||
|
@@ -54,7 +54,7 @@ type {{.schema.CodeName}}Interface interface {
|
||||
List(opts metav1.ListOptions) (*{{.schema.CodeName}}List, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
Controller() ({{.schema.CodeName}}Controller, error)
|
||||
Controller() {{.schema.CodeName}}Controller
|
||||
}
|
||||
|
||||
type {{.schema.ID}}Controller struct {
|
||||
@@ -85,35 +85,30 @@ func (c {{.schema.ID}}Factory) List() runtime.Object {
|
||||
return &{{.schema.CodeName}}List{}
|
||||
}
|
||||
|
||||
func New{{.schema.CodeName}}Client(namespace string, config rest.Config) ({{.schema.CodeName}}Interface, error) {
|
||||
objectClient, err := clientbase.NewObjectClient(namespace, config, &{{.schema.CodeName}}Resource, {{.schema.CodeName}}GroupVersionKind, {{.schema.ID}}Factory{})
|
||||
return &{{.schema.ID}}Client{
|
||||
objectClient: objectClient,
|
||||
}, err
|
||||
}
|
||||
func (s *{{.schema.ID}}Client) Controller() {{.schema.CodeName}}Controller {
|
||||
s.client.Lock()
|
||||
defer s.client.Unlock()
|
||||
|
||||
func (s *{{.schema.ID}}Client) Controller() ({{.schema.CodeName}}Controller, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.controller != nil {
|
||||
return s.controller, nil
|
||||
c, ok := s.client.{{.schema.ID}}Controllers[s.ns]
|
||||
if ok {
|
||||
return c
|
||||
}
|
||||
|
||||
controller, err := controller.NewGenericController({{.schema.CodeName}}GroupVersionKind.Kind+"Controller",
|
||||
genericController := controller.NewGenericController({{.schema.CodeName}}GroupVersionKind.Kind+"Controller",
|
||||
s.objectClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
c = &{{.schema.ID}}Controller{
|
||||
GenericController: genericController,
|
||||
}
|
||||
|
||||
s.controller = &{{.schema.ID}}Controller{
|
||||
GenericController: controller,
|
||||
}
|
||||
return s.controller, nil
|
||||
s.client.{{.schema.ID}}Controllers[s.ns] = c
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
type {{.schema.ID}}Client struct {
|
||||
sync.Mutex
|
||||
client *Client
|
||||
ns string
|
||||
objectClient *clientbase.ObjectClient
|
||||
controller {{.schema.CodeName}}Controller
|
||||
}
|
||||
|
@@ -149,6 +149,27 @@ func generateController(outputDir string, schema *types.Schema, schemas *types.S
|
||||
})
|
||||
}
|
||||
|
||||
func generateK8sClient(outputDir string, version *types.APIVersion, schemas []*types.Schema) error {
|
||||
filePath := strings.ToLower("zz_generated_k8s_client.go")
|
||||
output, err := os.Create(path.Join(outputDir, filePath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
typeTemplate, err := template.New("k8sClient.template").
|
||||
Funcs(funcs()).
|
||||
Parse(strings.Replace(k8sClientTemplate, "%BACK%", "`", -1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return typeTemplate.Execute(output, map[string]interface{}{
|
||||
"version": version,
|
||||
"schemas": schemas,
|
||||
})
|
||||
}
|
||||
|
||||
func generateClient(outputDir string, schemas []*types.Schema) error {
|
||||
template, err := template.New("client.template").
|
||||
Funcs(funcs()).
|
||||
@@ -177,7 +198,7 @@ func Generate(schemas *types.Schemas, cattleOutputPackage, k8sOutputPackage stri
|
||||
return err
|
||||
}
|
||||
|
||||
doDeepCopy := false
|
||||
controllers := []*types.Schema{}
|
||||
|
||||
generated := []*types.Schema{}
|
||||
for _, schema := range schemas.Schemas() {
|
||||
@@ -192,7 +213,7 @@ func Generate(schemas *types.Schemas, cattleOutputPackage, k8sOutputPackage stri
|
||||
if contains(schema.CollectionMethods, http.MethodGet) &&
|
||||
!strings.HasPrefix(schema.PkgName, "k8s.io") &&
|
||||
!strings.Contains(schema.PkgName, "/vendor/") {
|
||||
doDeepCopy = true
|
||||
controllers = append(controllers, schema)
|
||||
if err := generateController(k8sDir, schema, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -205,10 +226,12 @@ func Generate(schemas *types.Schemas, cattleOutputPackage, k8sOutputPackage stri
|
||||
return err
|
||||
}
|
||||
|
||||
if doDeepCopy {
|
||||
if len(controllers) > 0 {
|
||||
if err := deepCopyGen(baseDir, k8sOutputPackage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
generateK8sClient(k8sDir, &controllers[0].Version, controllers)
|
||||
}
|
||||
|
||||
if err := gofmt(baseDir, k8sOutputPackage); err != nil {
|
||||
|
62
generator/k8s_client_template.go
Normal file
62
generator/k8s_client_template.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package generator
|
||||
|
||||
var k8sClientTemplate = `package {{.version.Version}}
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/rancher/norman/clientbase"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
{{range .schemas}}
|
||||
{{.CodeNamePlural}}Getter{{end}}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
sync.Mutex
|
||||
restClient rest.Interface
|
||||
{{range .schemas}}
|
||||
{{.ID}}Controllers map[string]{{.CodeName}}Controller{{end}}
|
||||
}
|
||||
|
||||
func NewForConfig(config rest.Config) (Interface, error) {
|
||||
if config.NegotiatedSerializer == nil {
|
||||
configConfig := dynamic.ContentConfig()
|
||||
config.NegotiatedSerializer = configConfig.NegotiatedSerializer
|
||||
}
|
||||
|
||||
restClient, err := rest.UnversionedRESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
restClient: restClient,
|
||||
{{range .schemas}}
|
||||
{{.ID}}Controllers: map[string]{{.CodeName}}Controller{},{{end}}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) RESTClient() rest.Interface {
|
||||
return c.restClient
|
||||
}
|
||||
|
||||
{{range .schemas}}
|
||||
type {{.CodeNamePlural}}Getter interface {
|
||||
{{.CodeNamePlural}}(namespace string) {{.CodeName}}Interface
|
||||
}
|
||||
|
||||
func (c *Client) {{.CodeNamePlural}}(namespace string) {{.CodeName}}Interface {
|
||||
objectClient := clientbase.NewObjectClient(namespace, c.restClient, &{{.CodeName}}Resource, {{.CodeName}}GroupVersionKind, {{.ID}}Factory{})
|
||||
return &{{.ID}}Client{
|
||||
ns: namespace,
|
||||
client: c,
|
||||
objectClient: objectClient,
|
||||
}
|
||||
}
|
||||
{{end}}
|
||||
`
|
@@ -61,13 +61,22 @@ func (c *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id stri
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.back(result.Object, schema)
|
||||
c.fromInternal(result.Object, schema)
|
||||
|
||||
return result.Object, nil
|
||||
}
|
||||
|
||||
func (c *Store) back(data map[string]interface{}, schema *types.Schema) {
|
||||
//mapping.Metadata.Back(data)
|
||||
func (c *Store) toInternal(data map[string]interface{}, schema *types.Schema) {
|
||||
if schema.Mapper != nil {
|
||||
schema.Mapper.ToInternal(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Store) fromInternal(data map[string]interface{}, schema *types.Schema) {
|
||||
if schema.Mapper != nil {
|
||||
schema.Mapper.FromInternal(data)
|
||||
}
|
||||
|
||||
data["type"] = schema.ID
|
||||
name, _ := data["name"].(string)
|
||||
namespace, _ := data["namespace"].(string)
|
||||
@@ -79,6 +88,12 @@ func (c *Store) back(data map[string]interface{}, schema *types.Schema) {
|
||||
data["id"] = namespace + ":" + name
|
||||
}
|
||||
}
|
||||
|
||||
if status, ok := c.schemaStatus[schema]; ok {
|
||||
if status.Spec.Scope != apiext.NamespaceScoped {
|
||||
delete(data, "namespace")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Store) Delete(apiContext *types.APIContext, schema *types.Schema, id string) error {
|
||||
@@ -131,7 +146,7 @@ func (c *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *ty
|
||||
result := []map[string]interface{}{}
|
||||
|
||||
for _, obj := range resultList.Items {
|
||||
c.back(obj.Object, schema)
|
||||
c.fromInternal(obj.Object, schema)
|
||||
result = append(result, obj.Object)
|
||||
}
|
||||
|
||||
@@ -167,7 +182,8 @@ func (c *Store) Update(apiContext *types.APIContext, schema *types.Schema, data
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//mapping.Metadata.Forward(data)
|
||||
c.fromInternal(result.Object, schema)
|
||||
|
||||
for k, v := range data {
|
||||
if k == "metadata" {
|
||||
continue
|
||||
@@ -175,6 +191,8 @@ func (c *Store) Update(apiContext *types.APIContext, schema *types.Schema, data
|
||||
result.Object[k] = v
|
||||
}
|
||||
|
||||
c.toInternal(result.Object, schema)
|
||||
|
||||
req = c.k8sClient.Put().
|
||||
Prefix("apis", crd.Spec.Group, crd.Spec.Version).
|
||||
Resource(crd.Status.AcceptedNames.Plural).
|
||||
@@ -191,7 +209,7 @@ func (c *Store) Update(apiContext *types.APIContext, schema *types.Schema, data
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.back(result.Object, schema)
|
||||
c.fromInternal(result.Object, schema)
|
||||
return result.Object, nil
|
||||
}
|
||||
|
||||
@@ -208,6 +226,8 @@ func (c *Store) Create(apiContext *types.APIContext, schema *types.Schema, data
|
||||
data["apiVersion"] = crd.Spec.Group + "/" + crd.Spec.Version
|
||||
data["kind"] = crd.Status.AcceptedNames.Kind
|
||||
|
||||
c.toInternal(data, schema)
|
||||
|
||||
req := c.k8sClient.Post().
|
||||
Prefix("apis", crd.Spec.Group, crd.Spec.Version).
|
||||
Body(&unstructured.Unstructured{
|
||||
@@ -225,7 +245,7 @@ func (c *Store) Create(apiContext *types.APIContext, schema *types.Schema, data
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.back(result.Object, schema)
|
||||
c.fromInternal(result.Object, schema)
|
||||
return result.Object, nil
|
||||
}
|
||||
|
||||
|
@@ -48,7 +48,7 @@ func (t *TypeMapper) FromInternal(data map[string]interface{}) {
|
||||
}
|
||||
|
||||
func (t *TypeMapper) ToInternal(data map[string]interface{}) {
|
||||
for i := len(t.Mappers) - 1; i <= 0; i-- {
|
||||
for i := len(t.Mappers) - 1; i >= 0; i-- {
|
||||
t.Mappers[i].ToInternal(data)
|
||||
}
|
||||
|
||||
|
@@ -12,13 +12,15 @@ type Move struct {
|
||||
}
|
||||
|
||||
func (m Move) FromInternal(data map[string]interface{}) {
|
||||
if v, ok := GetValue(data, m.From); ok {
|
||||
if v, ok := data[m.From]; ok {
|
||||
delete(data, m.From)
|
||||
data[m.To] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (m Move) ToInternal(data map[string]interface{}) {
|
||||
if v, ok := GetValue(data, m.To); ok {
|
||||
if v, ok := data[m.To]; ok {
|
||||
delete(data, m.To)
|
||||
data[m.From] = v
|
||||
}
|
||||
}
|
||||
|
19
types/mapping/mapper/object.go
Normal file
19
types/mapping/mapper/object.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package mapper
|
||||
|
||||
import "github.com/rancher/norman/types"
|
||||
|
||||
type Object struct {
|
||||
types.TypeMapper
|
||||
}
|
||||
|
||||
func NewObject(mappers []types.Mapper) *Object {
|
||||
return &Object{
|
||||
TypeMapper: types.TypeMapper{
|
||||
Mappers: append(mappers,
|
||||
&Drop{"status"},
|
||||
&Embed{Field: "metadata"},
|
||||
&Embed{Field: "spec"},
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
@@ -55,6 +55,9 @@ func (s *Schemas) AddSchema(schema *Schema) *Schemas {
|
||||
if schema.CodeName == "" {
|
||||
schema.CodeName = convert.Capitalize(schema.ID)
|
||||
}
|
||||
if schema.CodeNamePlural == "" {
|
||||
schema.CodeNamePlural = name.GuessPluralName(schema.CodeName)
|
||||
}
|
||||
|
||||
schemas, ok := s.schemasByPath[schema.Version.Path]
|
||||
if !ok {
|
||||
|
@@ -62,6 +62,7 @@ type APIVersion struct {
|
||||
type Schema struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
CodeName string `json:"-"`
|
||||
CodeNamePlural string `json:"-"`
|
||||
PkgName string `json:"-"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Links map[string]string `json:"links"`
|
||||
|
Reference in New Issue
Block a user