Skip to content
This repository has been archived by the owner on Apr 25, 2024. It is now read-only.

Commit

Permalink
Merge pull request #57 from FabianKramm/refactor
Browse files Browse the repository at this point in the history
Automatically generate crds
  • Loading branch information
FabianKramm authored Apr 17, 2020
2 parents 924f96d + 12a9699 commit 06b8abe
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 92 deletions.
22 changes: 0 additions & 22 deletions chart/crds/config.kiosk.sh_accountquotas.yaml

This file was deleted.

22 changes: 0 additions & 22 deletions chart/crds/config.kiosk.sh_accounts.yaml

This file was deleted.

22 changes: 0 additions & 22 deletions chart/crds/config.kiosk.sh_templateinstances.yaml

This file was deleted.

22 changes: 0 additions & 22 deletions chart/crds/config.kiosk.sh_templates.yaml

This file was deleted.

31 changes: 30 additions & 1 deletion cmd/kiosk/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ import (
_ "github.com/kiosk-sh/kiosk/pkg/apiserver/registry"
"github.com/kiosk-sh/kiosk/pkg/openapi"
"github.com/kiosk-sh/kiosk/pkg/store/apiservice"
"github.com/kiosk-sh/kiosk/pkg/store/crd"
"github.com/kiosk-sh/kiosk/pkg/store/validatingwebhookconfiguration"
"github.com/kiosk-sh/kiosk/pkg/util/certhelper"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/client-go/rest"
"k8s.io/klog"
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
"os"
client2 "sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -82,7 +85,17 @@ func main() {
os.Exit(1)
}

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
// retrieve in cluster config
config := ctrl.GetConfigOrDie()

// Make sure the needed crds are installed in the cluster
err = initialize(config)
if err != nil {
klog.Fatal(err)
}

// create the manager
mgr, err := ctrl.NewManager(config, ctrl.Options{
Scheme: scheme,
MetricsBindAddress: ":8080",
LeaderElection: false,
Expand Down Expand Up @@ -174,6 +187,22 @@ func main() {
<-stopChan
}

func initialize(config *rest.Config) error {
klog.Info("Initialize...")
defer klog.Info("Done initializing...")

client, err := client2.New(config, client2.Options{Scheme: scheme})
if err != nil {
return err
}

klog.Info("Installing crds...")

builder := crd.NewBuilder(client)
_, err = builder.CreateCRDs(context.Background(), apis.TypeDefinitions...)
return err
}

func injectClient(client client2.Client, scheme *runtime.Scheme) {
tenancy.Client = client
tenancy.Scheme = scheme
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c // indirect
github.com/pkg/errors v0.8.1
github.com/rancher/kine v0.3.2 // indirect
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect
Expand Down
37 changes: 37 additions & 0 deletions pkg/apis/crds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package apis

import (
configv1alpha1 "github.com/kiosk-sh/kiosk/pkg/apis/config/v1alpha1"
"github.com/kiosk-sh/kiosk/pkg/store/crd"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
)

var (
// TypeDefinitions to create the appropriate crds
TypeDefinitions = []*crd.TypeDefinition{
&crd.TypeDefinition{
GVK: configv1alpha1.SchemeGroupVersion.WithKind("Account"),
Singular: "account",
Plural: "accounts",
Scope: apiextensionsv1beta1.ClusterScoped,
},
&crd.TypeDefinition{
GVK: configv1alpha1.SchemeGroupVersion.WithKind("AccountQuota"),
Singular: "accountquota",
Plural: "accountquotas",
Scope: apiextensionsv1beta1.ClusterScoped,
},
&crd.TypeDefinition{
GVK: configv1alpha1.SchemeGroupVersion.WithKind("Template"),
Singular: "template",
Plural: "templates",
Scope: apiextensionsv1beta1.ClusterScoped,
},
&crd.TypeDefinition{
GVK: configv1alpha1.SchemeGroupVersion.WithKind("TemplateInstance"),
Singular: "templateinstance",
Plural: "templateinstances",
Scope: apiextensionsv1beta1.NamespaceScoped,
},
}
)
15 changes: 12 additions & 3 deletions pkg/apiserver/registry/account/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func ConvertConfigAccount(configAccount *config.Account) (*tenancy.Account, erro
return nil, err
}

outAccount := &tenancy.Account{}
outAccount := &tenancyv1alpha1.Account{}
err = json.Unmarshal(out, outAccount)
if err != nil {
return nil, err
Expand All @@ -44,11 +44,20 @@ func ConvertConfigAccount(configAccount *config.Account) (*tenancy.Account, erro
APIVersion: tenancyv1alpha1.SchemeGroupVersion.String(),
}
outAccount.ObjectMeta = *configAccount.ObjectMeta.DeepCopy()
return outAccount, nil

tenancyAccount := &tenancy.Account{}
err = tenancyv1alpha1.Convert_v1alpha1_Account_To_tenancy_Account(outAccount, tenancyAccount, nil)
return tenancyAccount, err
}

// ConvertTenancyAccount converts a tenancy account into a config account
func ConvertTenancyAccount(tenancyAccount *tenancy.Account) (*config.Account, error) {
func ConvertTenancyAccount(originalAccount *tenancy.Account) (*config.Account, error) {
tenancyAccount := &tenancyv1alpha1.Account{}
err := tenancyv1alpha1.Convert_tenancy_Account_To_v1alpha1_Account(originalAccount, tenancyAccount, nil)
if err != nil {
return nil, err
}

out, err := json.Marshal(tenancyAccount)
if err != nil {
return nil, err
Expand Down
161 changes: 161 additions & 0 deletions pkg/store/crd/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package crd

import (
"context"
"strings"
"time"

"github.com/sirupsen/logrus"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/klog"

"sigs.k8s.io/controller-runtime/pkg/client"
)

// Builder is the interface to build crds from types
type Builder interface {
CreateCRDs(ctx context.Context, types ...*TypeDefinition) (map[*TypeDefinition]*apiextensionsv1beta1.CustomResourceDefinition, error)
}

// NewBuilder creates a new crd builder
func NewBuilder(client client.Client) Builder {
return &builder{
client: client,
}
}

type builder struct {
client client.Client
}

func (b *builder) CreateCRDs(ctx context.Context, types ...*TypeDefinition) (map[*TypeDefinition]*apiextensionsv1beta1.CustomResourceDefinition, error) {
typesStatus := map[*TypeDefinition]*apiextensionsv1beta1.CustomResourceDefinition{}

ready, err := GetReadyCRDs(ctx, b.client)
if err != nil {
return nil, err
}

for _, t := range types {
crd, err := b.createCRD(ctx, t, ready)
if err != nil {
return nil, err
}
typesStatus[t] = crd
}

ready, err = GetReadyCRDs(ctx, b.client)
if err != nil {
return nil, err
}

for t, crd := range typesStatus {
if readyCrd, ok := ready[crd.Name]; ok {
typesStatus[t] = readyCrd
} else {
if err := b.waitCRD(ctx, crd.Name, t, typesStatus); err != nil {
return nil, err
}
}
}

return typesStatus, nil
}

func (b *builder) waitCRD(ctx context.Context, crdName string, t *TypeDefinition, typesStatus map[*TypeDefinition]*apiextensionsv1beta1.CustomResourceDefinition) error {
klog.Infof("Waiting for CRD %s to become available", crdName)
defer klog.Infof("Done waiting for CRD %s to become available", crdName)

first := true
return wait.Poll(500*time.Millisecond, 60*time.Second, func() (bool, error) {
if !first {
logrus.Infof("Waiting for CRD %s to become available", crdName)
}
first = false

crd := &apiextensionsv1beta1.CustomResourceDefinition{}
err := b.client.Get(ctx, types.NamespacedName{Name: crdName}, crd)
if err != nil {
return false, err
}

for _, cond := range crd.Status.Conditions {
switch cond.Type {
case apiextensionsv1beta1.Established:
if cond.Status == apiextensionsv1beta1.ConditionTrue {
typesStatus[t] = crd
return true, err
}
case apiextensionsv1beta1.NamesAccepted:
if cond.Status == apiextensionsv1beta1.ConditionFalse {
klog.Infof("Name conflict on %s: %v\n", crdName, cond.Reason)
}
}
}

return false, ctx.Err()
})
}

func (b *builder) createCRD(ctx context.Context, t *TypeDefinition, ready map[string]*apiextensionsv1beta1.CustomResourceDefinition) (*apiextensionsv1beta1.CustomResourceDefinition, error) {
name := strings.ToLower(t.Plural + "." + t.GVK.Group)
crd, ok := ready[name]
if ok {
return crd, nil
}

crd = &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: t.GVK.Group,
Version: t.GVK.Version,
Scope: t.Scope,
Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
},
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: t.Plural,
Singular: t.Singular,
Kind: t.GVK.Kind,
},
},
}

klog.Infof("Creating CRD %s", name)
err := b.client.Create(ctx, crd)
if kerrors.IsAlreadyExists(err) {
return crd, nil
}

return crd, err
}

func GetReadyCRDs(ctx context.Context, client client.Client) (map[string]*apiextensionsv1beta1.CustomResourceDefinition, error) {
list := &apiextensionsv1beta1.CustomResourceDefinitionList{}

// List existing custom resource definitions
err := client.List(ctx, list)
if err != nil {
return nil, err
}

result := map[string]*apiextensionsv1beta1.CustomResourceDefinition{}
for i, crd := range list.Items {
for _, cond := range crd.Status.Conditions {
switch cond.Type {
case apiextensionsv1beta1.Established:
if cond.Status == apiextensionsv1beta1.ConditionTrue {
result[crd.Name] = &list.Items[i]
}
}
}
}

return result, nil
}
Loading

0 comments on commit 06b8abe

Please sign in to comment.