Skip to content

Commit

Permalink
feat(catalog): add grpc sourcetype to CatalogSources
Browse files Browse the repository at this point in the history
grpc sourcetype takes a new `image` field which specifies an image
which is expected to serve a registry API over grpc on port 50051.
  • Loading branch information
ecordell committed Jan 10, 2019
1 parent 5a4031b commit ead6afc
Show file tree
Hide file tree
Showing 12 changed files with 837 additions and 187 deletions.
5 changes: 5 additions & 0 deletions deploy/chart/templates/0000_30_05-catalogsource.crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,16 @@ spec:
enum:
- internal # deprecated
- configmap
- grpc

configMap:
type: string
description: The name of a ConfigMap that holds the entries for an in-memory catalog.

image:
type: string
description: An image that serves a grpc registry. Only valid for `grpc` sourceType.

displayName:
type: string
description: Pretty name for display
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/apis/operators/v1alpha1/catalogsource_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ type SourceType string
const (
SourceTypeInternal SourceType = "internal"
SourceTypeConfigmap SourceType = "configmap"
SourceTypeGrpc SourceType = "grpc"
)

type CatalogSourceSpec struct {
SourceType SourceType `json:"sourceType"`
ConfigMap string `json:"configMap,omitempty"`
Image string `json:"image,omitempty"`
Secrets []string `json:"secrets,omitempty"`

// Metadata
Expand Down
144 changes: 76 additions & 68 deletions pkg/controller/operators/catalog/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/informers/externalversions"
olmerrors "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/errors"
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry"
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler"
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver"
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister"
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
Expand All @@ -54,16 +54,16 @@ var timeNow = func() metav1.Time { return metav1.NewTime(time.Now().UTC()) }
// resolving dependencies in a catalog.
type Operator struct {
*queueinformer.Operator
client versioned.Interface
lister operatorlister.OperatorLister
namespace string
sources map[resolver.CatalogKey]resolver.SourceRef
sourcesLock sync.RWMutex
sourcesLastUpdate metav1.Time
resolver resolver.Resolver
subQueue workqueue.RateLimitingInterface
catSrcQueue workqueue.RateLimitingInterface
configmapRegistryReconciler registry.RegistryReconciler
client versioned.Interface
lister operatorlister.OperatorLister
namespace string
sources map[resolver.CatalogKey]resolver.SourceRef
sourcesLock sync.RWMutex
sourcesLastUpdate metav1.Time
resolver resolver.Resolver
subQueue workqueue.RateLimitingInterface
catSrcQueue workqueue.RateLimitingInterface
reconciler reconciler.ReconcilerReconciler
}

// NewOperator creates a new Catalog Operator.
Expand Down Expand Up @@ -207,10 +207,10 @@ func NewOperator(kubeconfigPath string, logger *logrus.Logger, wakeupInterval ti
op.lister.CoreV1().RegisterPodLister(namespace, podInformer.Lister())
op.lister.CoreV1().RegisterConfigMapLister(namespace, configMapInformer.Lister())
}
op.configmapRegistryReconciler = &registry.ConfigMapRegistryReconciler{
Image: configmapRegistryImage,
OpClient: op.OpClient,
Lister: op.lister,
op.reconciler = &reconciler.RegistryReconcilerReconciler{
ConfigMapServerImage: configmapRegistryImage,
OpClient: op.OpClient,
Lister: op.lister,
}
return op, nil
}
Expand Down Expand Up @@ -281,15 +281,29 @@ func (o *Operator) handleDeletion(obj interface{}) {
}

func (o *Operator) handleCatSrcDeletion(obj interface{}) {
if catsrc, ok := obj.(*v1alpha1.CatalogSource); ok {
sourceKey := resolver.CatalogKey{Name: catsrc.GetName(), Namespace: catsrc.GetNamespace()}
func() {
o.sourcesLock.Lock()
defer o.sourcesLock.Unlock()
delete(o.sources, sourceKey)
}()
o.Log.WithField("source", sourceKey).Info("removed client for deleted catalogsource")
catsrc, ok := obj.(metav1.Object)
if !ok {
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
utilruntime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
return
}

catsrc, ok = tombstone.Obj.(metav1.Object)
if !ok {
utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a Namespace %#v", obj))
return
}
}
}
sourceKey := resolver.CatalogKey{Name: catsrc.GetName(), Namespace: catsrc.GetNamespace()}
func() {
o.sourcesLock.Lock()
defer o.sourcesLock.Unlock()
delete(o.sources, sourceKey)
}()
o.Log.WithField("source", sourceKey).Info("removed client for deleted catalogsource")
}

func (o *Operator) syncCatalogSources(obj interface{}) (syncError error) {
Expand All @@ -303,53 +317,45 @@ func (o *Operator) syncCatalogSources(obj interface{}) (syncError error) {
"source": catsrc.GetName(),
})

if catsrc.Spec.SourceType == v1alpha1.SourceTypeInternal || catsrc.Spec.SourceType == v1alpha1.SourceTypeConfigmap {
return o.syncConfigMapSource(logger, catsrc)
}

logger.WithField("sourceType", catsrc.Spec.SourceType).Warn("unknown source type")

// TODO: write status about invalid source type

return nil
}

func (o *Operator) syncConfigMapSource(logger *logrus.Entry, catsrc *v1alpha1.CatalogSource) (syncError error) {
// Get the catalog source's config map
configMap, err := o.lister.CoreV1().ConfigMapLister().ConfigMaps(catsrc.GetNamespace()).Get(catsrc.Spec.ConfigMap)
if err != nil {
return fmt.Errorf("failed to get catalog config map %s: %s", catsrc.Spec.ConfigMap, err)
}

out := catsrc.DeepCopy()
sourceKey := resolver.CatalogKey{Name: catsrc.GetName(), Namespace: catsrc.GetNamespace()}

if catsrc.Status.ConfigMapResource == nil || catsrc.Status.ConfigMapResource.UID != configMap.GetUID() || catsrc.Status.ConfigMapResource.ResourceVersion != configMap.GetResourceVersion() {
// configmap ref nonexistent or updated, write out the new configmap ref to status and exit
out.Status.ConfigMapResource = &v1alpha1.ConfigMapResourceReference{
Name: configMap.GetName(),
Namespace: configMap.GetNamespace(),
UID: configMap.GetUID(),
ResourceVersion: configMap.GetResourceVersion(),
if catsrc.Spec.SourceType == v1alpha1.SourceTypeInternal || catsrc.Spec.SourceType == v1alpha1.SourceTypeConfigmap {
// Get the catalog source's config map
configMap, err := o.lister.CoreV1().ConfigMapLister().ConfigMaps(catsrc.GetNamespace()).Get(catsrc.Spec.ConfigMap)
if err != nil {
return fmt.Errorf("failed to get catalog config map %s: %s", catsrc.Spec.ConfigMap, err)
}
out.Status.LastSync = timeNow()

// update status
if _, err = o.client.OperatorsV1alpha1().CatalogSources(out.GetNamespace()).UpdateStatus(out); err != nil {
return err
}
if catsrc.Status.ConfigMapResource == nil || catsrc.Status.ConfigMapResource.UID != configMap.GetUID() || catsrc.Status.ConfigMapResource.ResourceVersion != configMap.GetResourceVersion() {
// configmap ref nonexistent or updated, write out the new configmap ref to status and exit
out.Status.ConfigMapResource = &v1alpha1.ConfigMapResourceReference{
Name: configMap.GetName(),
Namespace: configMap.GetNamespace(),
UID: configMap.GetUID(),
ResourceVersion: configMap.GetResourceVersion(),
}
out.Status.LastSync = timeNow()

o.sourcesLastUpdate = timeNow()
// update status
if _, err = o.client.OperatorsV1alpha1().CatalogSources(out.GetNamespace()).UpdateStatus(out); err != nil {
return err
}

return nil
o.sourcesLastUpdate = timeNow()

return nil
}
}

// configmap ref is up to date, continue parsing
if catsrc.Status.RegistryServiceStatus == nil || catsrc.Status.RegistryServiceStatus.CreatedAt.Before(&catsrc.Status.LastSync) {
// if registry pod hasn't been created or hasn't been updated since the last configmap update, recreate it
reconciler := o.reconciler.ReconcilerForSourceType(catsrc.Spec.SourceType)
if reconciler == nil {
return fmt.Errorf("no reconciler for source type %s", catsrc.Spec.SourceType)
}

out := catsrc.DeepCopy()
if err := o.configmapRegistryReconciler.EnsureRegistryServer(out); err != nil {
// if registry pod hasn't been created or hasn't been updated since the last configmap update, recreate it
if catsrc.Status.RegistryServiceStatus == nil || catsrc.Status.RegistryServiceStatus.CreatedAt.Before(&catsrc.Status.LastSync) {
if err := reconciler.EnsureRegistryServer(out); err != nil {
logger.WithError(err).Warn("couldn't ensure registry server")
return err
}
Expand All @@ -359,7 +365,7 @@ func (o *Operator) syncConfigMapSource(logger *logrus.Entry, catsrc *v1alpha1.Ca
}

// update status
if _, err = o.client.OperatorsV1alpha1().CatalogSources(out.GetNamespace()).UpdateStatus(out); err != nil {
if _, err := o.client.OperatorsV1alpha1().CatalogSources(out.GetNamespace()).UpdateStatus(out); err != nil {
return err
}

Expand All @@ -368,6 +374,7 @@ func (o *Operator) syncConfigMapSource(logger *logrus.Entry, catsrc *v1alpha1.Ca
return nil
}

// update operator's view of sources
sourcesUpdated := false
func() {
o.sourcesLock.Lock()
Expand All @@ -389,13 +396,14 @@ func (o *Operator) syncConfigMapSource(logger *logrus.Entry, catsrc *v1alpha1.Ca
}
}()

if sourcesUpdated {
// record that we've done work here onto the status
out := catsrc.DeepCopy()
out.Status.LastSync = timeNow()
if _, err = o.client.OperatorsV1alpha1().CatalogSources(out.GetNamespace()).UpdateStatus(out); err != nil {
return err
}
if !sourcesUpdated {
return nil
}

// record that we've done work here onto the status
out.Status.LastSync = timeNow()
if _, err := o.client.OperatorsV1alpha1().CatalogSources(out.GetNamespace()).UpdateStatus(out); err != nil {
return err
}

// Sync any dependent Subscriptions
Expand Down
10 changes: 5 additions & 5 deletions pkg/controller/operators/catalog/operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/fake"
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/informers/externalversions"
olmerrors "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/errors"
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry"
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler"
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver"
"github.com/operator-framework/operator-lifecycle-manager/pkg/fakes"
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
Expand Down Expand Up @@ -420,10 +420,10 @@ func NewFakeOperator(clientObjs []runtime.Object, k8sObjs []runtime.Object, extO
resolver: &fakes.FakeResolver{},
}

op.configmapRegistryReconciler = &registry.ConfigMapRegistryReconciler{
Image: "test:pod",
OpClient: op.OpClient,
Lister: lister,
op.reconciler = &reconciler.RegistryReconcilerReconciler{
ConfigMapServerImage: "test:pod",
OpClient: op.OpClient,
Lister: lister,
}

var hasSyncedCheckFns []cache.InformerSynced
Expand Down
Loading

0 comments on commit ead6afc

Please sign in to comment.