Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

code generation for crd clients #73

Merged
merged 3 commits into from
May 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,13 @@ clientset: $(GENERATED_PROTO_FILES) $(SOURCES)
$(PACKAGE_PATH)/pkg/storage/crd \
"solo.io:v1"

.PHONY: generated-code
generated-code:
go generate ./...

$(OUTPUT):
mkdir -p $(OUTPUT)

define BINARY_TARGETS
$(eval VERSION := $(shell cat cmd/$(BINARY)/version))
$(eval IMAGE_TAG ?= $(VERSION))
Expand Down
2 changes: 1 addition & 1 deletion pkg/plugins/grpc/annotations.google.descriptor.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// File generated by 2gobytes v0.4.2 (http://github.com/paulvollmer/2gobytes)
// date: 2018-03-26 17:11:23.759194828 -0400 EDT m=+0.003949926
// date: 2018-04-30 15:35:58.274663731 -0400 EDT m=+0.004028854

package grpc

Expand Down
2 changes: 1 addition & 1 deletion pkg/plugins/grpc/descriptors.google.descriptor.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// File generated by 2gobytes v0.4.2 (http://github.com/paulvollmer/2gobytes)
// date: 2018-03-26 17:11:24.473888857 -0400 EDT m=+0.640458305
// date: 2018-04-30 15:35:59.244912996 -0400 EDT m=+0.887079990

package grpc

Expand Down
2 changes: 1 addition & 1 deletion pkg/plugins/grpc/http.google.descriptor.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// File generated by 2gobytes v0.4.2 (http://github.com/paulvollmer/2gobytes)
// date: 2018-03-26 17:11:23.830848683 -0400 EDT m=+0.070306137
// date: 2018-04-30 15:35:58.355959251 -0400 EDT m=+0.079986258

package grpc

Expand Down
1 change: 1 addition & 0 deletions pkg/storage/crd/crd_storage_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
crdv1 "github.com/solo-io/gloo/pkg/storage/crd/solo.io/v1"
)

//go:generate go run ${GOPATH}/src/github.com/solo-io/gloo/pkg/storage/crd/solo.io/generate_clients.go
type Client struct {
v1 *v1client
}
Expand Down
171 changes: 171 additions & 0 deletions pkg/storage/crd/solo.io/client_template.go.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package crd

import (
"time"

"github.com/pkg/errors"
"github.com/solo-io/gloo/pkg/api/types/v1"
"github.com/solo-io/gloo/pkg/storage"
crdclientset "github.com/solo-io/gloo/pkg/storage/crd/client/clientset/versioned"
crdv1 "github.com/solo-io/gloo/pkg/storage/crd/solo.io/v1"
apiexts "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"

"github.com/solo-io/gloo/pkg/storage/crud"
kuberrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/tools/cache"
)

type {{ .LowercasePluralName }}Client struct {
crds crdclientset.Interface
apiexts apiexts.Interface
// write and read objects to this namespace if not specified on the GlooObjects
namespace string
syncFrequency time.Duration
}

func (c *{{ .LowercasePluralName }}Client) Create(item *v1.{{ .UppercaseName }}) (*v1.{{ .UppercaseName }}, error) {
return c.createOrUpdate{{ .UppercaseName }}Crd(item, crud.OperationCreate)
}

func (c *{{ .LowercasePluralName }}Client) Update(item *v1.{{ .UppercaseName }}) (*v1.{{ .UppercaseName }}, error) {
return c.createOrUpdate{{ .UppercaseName }}Crd(item, crud.OperationUpdate)
}

func (c *{{ .LowercasePluralName }}Client) Delete(name string) error {
return c.crds.GlooV1().{{ .UppercasePluralName }}(c.namespace).Delete(name, nil)
}

func (c *{{ .LowercasePluralName }}Client) Get(name string) (*v1.{{ .UppercaseName }}, error) {
crd{{ .UppercaseName }}, err := c.crds.GlooV1().{{ .UppercasePluralName }}(c.namespace).Get(name, metav1.GetOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed performing get api request")
}
returned{{ .UppercaseName }}, err := {{ .UppercaseName }}FromCrd(crd{{ .UppercaseName }})
if err != nil {
return nil, errors.Wrap(err, "converting returned crd to {{ .LowercaseName }}")
}
return returned{{ .UppercaseName }}, nil
}

func (c *{{ .LowercasePluralName }}Client) List() ([]*v1.{{ .UppercaseName }}, error) {
crdList, err := c.crds.GlooV1().{{ .UppercasePluralName }}(c.namespace).List(metav1.ListOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed performing list api request")
}
var returned{{ .UppercasePluralName }} []*v1.{{ .UppercaseName }}
for _, crd{{ .UppercaseName }} := range crdList.Items {
{{ .LowercaseName }}, err := {{ .UppercaseName }}FromCrd(&crd{{ .UppercaseName }})
if err != nil {
return nil, errors.Wrap(err, "converting returned crd to {{ .LowercaseName }}")
}
returned{{ .UppercasePluralName }} = append(returned{{ .UppercasePluralName }}, {{ .LowercaseName }})
}
return returned{{ .UppercasePluralName }}, nil
}

func (u *{{ .LowercasePluralName }}Client) Watch(handlers ...storage.{{ .UppercaseName }}EventHandler) (*storage.Watcher, error) {
lw := cache.NewListWatchFromClient(u.crds.GlooV1().RESTClient(), crdv1.{{ .UppercaseName }}CRD.Plural, u.namespace, fields.Everything())
sw := cache.NewSharedInformer(lw, new(crdv1.{{ .UppercaseName }}), u.syncFrequency)
for _, h := range handlers {
sw.AddEventHandler(&{{ .LowercaseName }}EventHandler{handler: h, store: sw.GetStore()})
}
return storage.NewWatcher(func(stop <-chan struct{}, _ chan error) {
sw.Run(stop)
}), nil
}

func (c *{{ .LowercasePluralName }}Client) createOrUpdate{{ .UppercaseName }}Crd({{ .LowercaseName }} *v1.{{ .UppercaseName }}, op crud.Operation) (*v1.{{ .UppercaseName }}, error) {
{{ .LowercaseName }}Crd, err := {{ .UppercaseName }}ToCrd(c.namespace, {{ .LowercaseName }})
if err != nil {
return nil, errors.Wrap(err, "converting gloo object to crd")
}
{{ .LowercasePluralName }} := c.crds.GlooV1().{{ .UppercasePluralName }}({{ .LowercaseName }}Crd.Namespace)
var returnedCrd *crdv1.{{ .UppercaseName }}
switch op {
case crud.OperationCreate:
returnedCrd, err = {{ .LowercasePluralName }}.Create({{ .LowercaseName }}Crd)
if err != nil {
if kuberrs.IsAlreadyExists(err) {
return nil, storage.NewAlreadyExistsErr(err)
}
return nil, errors.Wrap(err, "kubernetes create api request")
}
case crud.OperationUpdate:
// need to make sure we preserve labels
currentCrd, err := {{ .LowercasePluralName }}.Get({{ .LowercaseName }}Crd.Name, metav1.GetOptions{ResourceVersion: {{ .LowercaseName }}Crd.ResourceVersion})
if err != nil {
return nil, errors.Wrap(err, "kubernetes get api request")
}
// copy labels
{{ .LowercaseName }}Crd.Labels = currentCrd.Labels
returnedCrd, err = {{ .LowercasePluralName }}.Update({{ .LowercaseName }}Crd)
if err != nil {
return nil, errors.Wrap(err, "kubernetes update api request")
}
}
returned{{ .UppercaseName }}, err := {{ .UppercaseName }}FromCrd(returnedCrd)
if err != nil {
return nil, errors.Wrap(err, "converting returned crd to {{ .LowercaseName }}")
}
return returned{{ .UppercaseName }}, nil
}

// implements the kubernetes ResourceEventHandler interface
type {{ .LowercaseName }}EventHandler struct {
handler storage.{{ .UppercaseName }}EventHandler
store cache.Store
}

func (eh *{{ .LowercaseName }}EventHandler) getUpdatedList() []*v1.{{ .UppercaseName }} {
updatedList := eh.store.List()
var updated{{ .UppercaseName }}List []*v1.{{ .UppercaseName }}
for _, updated := range updatedList {
{{ .LowercaseName }}Crd, ok := updated.(*crdv1.{{ .UppercaseName }})
if !ok {
continue
}
updated{{ .UppercaseName }}, err := {{ .UppercaseName }}FromCrd({{ .LowercaseName }}Crd)
if err != nil {
continue
}
updated{{ .UppercaseName }}List = append(updated{{ .UppercaseName }}List, updated{{ .UppercaseName }})
}
return updated{{ .UppercaseName }}List
}

func convert{{ .UppercaseName }}(obj interface{}) (*v1.{{ .UppercaseName }}, bool) {
{{ .LowercaseName }}Crd, ok := obj.(*crdv1.{{ .UppercaseName }})
if !ok {
return nil, ok
}
{{ .LowercaseName }}, err := {{ .UppercaseName }}FromCrd({{ .LowercaseName }}Crd)
if err != nil {
return nil, false
}
return {{ .LowercaseName }}, ok
}

func (eh *{{ .LowercaseName }}EventHandler) OnAdd(obj interface{}) {
{{ .LowercaseName }}, ok := convert{{ .UppercaseName }}(obj)
if !ok {
return
}
eh.handler.OnAdd(eh.getUpdatedList(), {{ .LowercaseName }})
}
func (eh *{{ .LowercaseName }}EventHandler) OnUpdate(_, newObj interface{}) {
new{{ .UppercaseName }}, ok := convert{{ .UppercaseName }}(newObj)
if !ok {
return
}
eh.handler.OnUpdate(eh.getUpdatedList(), new{{ .UppercaseName }})
}

func (eh *{{ .LowercaseName }}EventHandler) OnDelete(obj interface{}) {
{{ .LowercaseName }}, ok := convert{{ .UppercaseName }}(obj)
if !ok {
return
}
eh.handler.OnDelete(eh.getUpdatedList(), {{ .LowercaseName }})
}
69 changes: 69 additions & 0 deletions pkg/storage/crd/solo.io/generate_clients.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package main

import (
"flag"
"github.com/solo-io/gloo/test/helpers"
"path/filepath"
"github.com/solo-io/gloo/pkg/log"
"github.com/pkg/errors"
"bytes"
"io/ioutil"
"text/template"
)

type clientType struct {
FilenamePrefix string
LowercaseName string
LowercasePluralName string
UppercaseName string
UppercasePluralName string
}

var clients = []clientType{
{
FilenamePrefix: "upstreams",
LowercaseName: "upstream",
LowercasePluralName: "upstreams",
UppercaseName: "Upstream",
UppercasePluralName: "Upstreams",
},
{
FilenamePrefix: "virtual_services",
LowercaseName: "virtualService",
LowercasePluralName: "virtualServices",
UppercaseName: "VirtualService",
UppercasePluralName: "VirtualServices",
},
}

func main() {
baseDir := filepath.Join(helpers.GlooSoloDirectory(), "pkg", "storage", "crd")
inputFile := flag.String("f", filepath.Join(baseDir, "solo.io", "client_template.go.tmpl"), "input client template")
outputDirectory := flag.String("o", baseDir, "output directory for client files")
flag.Parse()
if err := writeClientTemplates(*inputFile, *outputDirectory); err != nil {
log.Fatalf("failed generating client templates: %s", err.Error())
}
log.Printf("success")
}

func writeClientTemplates(inputFile, outputDir string) error {
fileName := filepath.Base(inputFile)
for _, client := range clients {
tmpl, err := template.New("Test_Resources").ParseFiles(inputFile)
if err != nil {
return errors.Wrap(err, "parsing template from "+inputFile)
}

buf := &bytes.Buffer{}
if err := tmpl.ExecuteTemplate(buf, fileName, client); err != nil {
return errors.Wrap(err, "executing template")
}

err = ioutil.WriteFile(filepath.Join(outputDir, client.FilenamePrefix+".go"), buf.Bytes(), 0644)
if err != nil {
return errors.Wrap(err, "writing generated client bytes")
}
}
return nil
}
32 changes: 16 additions & 16 deletions pkg/storage/crd/upstreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ func (c *upstreamsClient) Delete(name string) error {
}

func (c *upstreamsClient) Get(name string) (*v1.Upstream, error) {
crdUs, err := c.crds.GlooV1().Upstreams(c.namespace).Get(name, metav1.GetOptions{})
crdUpstream, err := c.crds.GlooV1().Upstreams(c.namespace).Get(name, metav1.GetOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed performing get api request")
}
returnedUpstream, err := UpstreamFromCrd(crdUs)
returnedUpstream, err := UpstreamFromCrd(crdUpstream)
if err != nil {
return nil, errors.Wrap(err, "converting returned crd to upstream")
}
Expand All @@ -55,8 +55,8 @@ func (c *upstreamsClient) List() ([]*v1.Upstream, error) {
return nil, errors.Wrap(err, "failed performing list api request")
}
var returnedUpstreams []*v1.Upstream
for _, crdUs := range crdList.Items {
upstream, err := UpstreamFromCrd(&crdUs)
for _, crdUpstream := range crdList.Items {
upstream, err := UpstreamFromCrd(&crdUpstream)
if err != nil {
return nil, errors.Wrap(err, "converting returned crd to upstream")
}
Expand Down Expand Up @@ -122,11 +122,11 @@ func (eh *upstreamEventHandler) getUpdatedList() []*v1.Upstream {
updatedList := eh.store.List()
var updatedUpstreamList []*v1.Upstream
for _, updated := range updatedList {
usCrd, ok := updated.(*crdv1.Upstream)
upstreamCrd, ok := updated.(*crdv1.Upstream)
if !ok {
continue
}
updatedUpstream, err := UpstreamFromCrd(usCrd)
updatedUpstream, err := UpstreamFromCrd(upstreamCrd)
if err != nil {
continue
}
Expand All @@ -135,37 +135,37 @@ func (eh *upstreamEventHandler) getUpdatedList() []*v1.Upstream {
return updatedUpstreamList
}

func convertUs(obj interface{}) (*v1.Upstream, bool) {
usCrd, ok := obj.(*crdv1.Upstream)
func convertUpstream(obj interface{}) (*v1.Upstream, bool) {
upstreamCrd, ok := obj.(*crdv1.Upstream)
if !ok {
return nil, ok
}
us, err := UpstreamFromCrd(usCrd)
upstream, err := UpstreamFromCrd(upstreamCrd)
if err != nil {
return nil, false
}
return us, ok
return upstream, ok
}

func (eh *upstreamEventHandler) OnAdd(obj interface{}) {
us, ok := convertUs(obj)
upstream, ok := convertUpstream(obj)
if !ok {
return
}
eh.handler.OnAdd(eh.getUpdatedList(), us)
eh.handler.OnAdd(eh.getUpdatedList(), upstream)
}
func (eh *upstreamEventHandler) OnUpdate(_, newObj interface{}) {
newUs, ok := convertUs(newObj)
newUpstream, ok := convertUpstream(newObj)
if !ok {
return
}
eh.handler.OnUpdate(eh.getUpdatedList(), newUs)
eh.handler.OnUpdate(eh.getUpdatedList(), newUpstream)
}

func (eh *upstreamEventHandler) OnDelete(obj interface{}) {
us, ok := convertUs(obj)
upstream, ok := convertUpstream(obj)
if !ok {
return
}
eh.handler.OnDelete(eh.getUpdatedList(), us)
eh.handler.OnDelete(eh.getUpdatedList(), upstream)
}
Loading