Skip to content
This repository has been archived by the owner on Jan 29, 2025. It is now read-only.

Commit

Permalink
Use dynamic REST mapper for the client
Browse files Browse the repository at this point in the history
  • Loading branch information
Artyom Lukianov committed Sep 10, 2019
1 parent f1f7911 commit aa31f4d
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 28 deletions.
1 change: 1 addition & 0 deletions cmd/machine-remediation-operator/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ go_library(
"//pkg/consts:go_default_library",
"//pkg/controllers:go_default_library",
"//pkg/operator:go_default_library",
"//pkg/utils/mapper:go_default_library",
"//pkg/version:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/openshift/api/config/v1:go_default_library",
Expand Down
4 changes: 3 additions & 1 deletion cmd/machine-remediation-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"kubevirt.io/machine-remediation-operator/pkg/consts"
"kubevirt.io/machine-remediation-operator/pkg/controllers"
"kubevirt.io/machine-remediation-operator/pkg/operator"
"kubevirt.io/machine-remediation-operator/pkg/utils/mapper"
"kubevirt.io/machine-remediation-operator/pkg/version"

"sigs.k8s.io/controller-runtime/pkg/cache"
Expand Down Expand Up @@ -45,7 +46,8 @@ func main() {
namespaces = append(namespaces, *namespace)
}
opts := manager.Options{
NewCache: cache.MultiNamespacedCacheBuilder(namespaces),
NewCache: cache.MultiNamespacedCacheBuilder(namespaces),
MapperProvider: mapper.NewDynamicRESTMapper,
}

// Create a new Cmd to provide shared dependencies and start components
Expand Down
16 changes: 16 additions & 0 deletions manifests/generated/machine-remediation-operator-csv.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,22 @@ spec:
- clusterrolebindings
verbs:
- '*'
- apiGroups:
- config.openshift.io
resources:
- infrastructures
- infrastructures/status
verbs:
- get
- list
- watch
- apiGroups:
- machineremediation.kubevirt.io
resources:
- machinedisruptionbudgets
- machinehealthchecks
verbs:
- '*'
serviceAccountName: machine-remediation-operator
deployments:
- name: machine-remediation-operator
Expand Down
16 changes: 0 additions & 16 deletions pkg/operator/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ type ReconcileMachineRemediationOperator struct {
// This client, initialized using mgr.Client() above, is a split client
// that reads objects from the cache and writes to the apiserver
client client.Client
updateClient client.Client
mgr manager.Manager
namespace string
operatorVersion string
crdsManifestsDir string
Expand All @@ -54,7 +52,6 @@ func Add(mgr manager.Manager, opts manager.Options) error {
func newReconciler(mgr manager.Manager, opts manager.Options) (reconcile.Reconciler, error) {
return &ReconcileMachineRemediationOperator{
client: mgr.GetClient(),
mgr: mgr,
namespace: opts.Namespace,
operatorVersion: os.Getenv(components.EnvVarOperatorVersion),
crdsManifestsDir: "/data",
Expand Down Expand Up @@ -195,19 +192,6 @@ func (r *ReconcileMachineRemediationOperator) createOrUpdateComponents(mro *mrv1

// deploy masters MachineHealthCheck and MachineDisruptionBudget only for BareMetal environment
if baremetal {
// TODO(alukiano): ugly W/A to get client that already has registred MHC and MDB CRD's
// this client does not use cache at all
if r.updateClient == nil {
opts := client.Options{
Scheme: r.mgr.GetScheme(),
}
c, err := client.New(r.mgr.GetConfig(), opts)
if err != nil {
return err
}
r.updateClient = c
}

if err := r.createOrUpdateMachineHealthCheck(consts.MasterMachineHealthCheck, consts.NamespaceOpenshiftMachineAPI); err != nil {
return err
}
Expand Down
5 changes: 2 additions & 3 deletions pkg/operator/operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,17 @@ func newFakeReconciler(initObjects ...runtime.Object) *ReconcileMachineRemediati
fakeClient := fake.NewFakeClient(initObjects...)
return &ReconcileMachineRemediationOperator{
client: fakeClient,
updateClient: fakeClient,
namespace: consts.NamespaceOpenshiftMachineAPI,
operatorVersion: imageTag,
crdsManifestsDir: "../../manifests/generated/crds",
}
}

func testReconcile(t *testing.T, platform osconfigv1.PlatformType) {
ifrastructure := mrotesting.NewInfrastructure("cluster", platform)
infrastructure := mrotesting.NewInfrastructure("cluster", platform)
mro := newMachineRemediationOperator("mro")

r := newFakeReconciler(mro, ifrastructure)
r := newFakeReconciler(mro, infrastructure)
request := reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: consts.NamespaceOpenshiftMachineAPI,
Expand Down
16 changes: 8 additions & 8 deletions pkg/operator/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ func (r *ReconcileMachineRemediationOperator) getMachineHealthCheck(name string,
Name: name,
Namespace: namespace,
}
if err := r.updateClient.Get(context.TODO(), key, mhc); err != nil {
if err := r.client.Get(context.TODO(), key, mhc); err != nil {
return nil, err
}
return mhc, nil
Expand All @@ -342,7 +342,7 @@ func (r *ReconcileMachineRemediationOperator) createOrUpdateMachineHealthCheck(n

oldMachineHealthCheck, err := r.getMachineHealthCheck(name, namespace)
if errors.IsNotFound(err) {
if err := r.updateClient.Create(context.TODO(), newMachineHealthCheck); err != nil {
if err := r.client.Create(context.TODO(), newMachineHealthCheck); err != nil {
return err
}
return nil
Expand All @@ -353,7 +353,7 @@ func (r *ReconcileMachineRemediationOperator) createOrUpdateMachineHealthCheck(n
}

newMachineHealthCheck.ResourceVersion = oldMachineHealthCheck.ResourceVersion
return r.updateClient.Update(context.TODO(), newMachineHealthCheck)
return r.client.Update(context.TODO(), newMachineHealthCheck)
}

func (r *ReconcileMachineRemediationOperator) deleteMachineHealthCheck(name string, namespace string) error {
Expand All @@ -364,7 +364,7 @@ func (r *ReconcileMachineRemediationOperator) deleteMachineHealthCheck(name stri
if err != nil {
return err
}
return r.updateClient.Delete(context.TODO(), mhc)
return r.client.Delete(context.TODO(), mhc)
}

func (r *ReconcileMachineRemediationOperator) getMachineDisruptionBudget(name string, namespace string) (*mrv1.MachineDisruptionBudget, error) {
Expand All @@ -373,7 +373,7 @@ func (r *ReconcileMachineRemediationOperator) getMachineDisruptionBudget(name st
Name: name,
Namespace: namespace,
}
if err := r.updateClient.Get(context.TODO(), key, mdb); err != nil {
if err := r.client.Get(context.TODO(), key, mdb); err != nil {
return nil, err
}
return mdb, nil
Expand All @@ -384,7 +384,7 @@ func (r *ReconcileMachineRemediationOperator) createOrUpdateMachineDisruptionBud

oldMachineDisruptionBudget, err := r.getMachineDisruptionBudget(name, namespace)
if errors.IsNotFound(err) {
if err := r.updateClient.Create(context.TODO(), newMachineDisruptionBudget); err != nil {
if err := r.client.Create(context.TODO(), newMachineDisruptionBudget); err != nil {
return err
}
return nil
Expand All @@ -395,7 +395,7 @@ func (r *ReconcileMachineRemediationOperator) createOrUpdateMachineDisruptionBud
}

newMachineDisruptionBudget.ResourceVersion = oldMachineDisruptionBudget.ResourceVersion
return r.updateClient.Update(context.TODO(), newMachineDisruptionBudget)
return r.client.Update(context.TODO(), newMachineDisruptionBudget)
}

func (r *ReconcileMachineRemediationOperator) deleteMachineDisruptionBudget(name string, namespace string) error {
Expand All @@ -406,7 +406,7 @@ func (r *ReconcileMachineRemediationOperator) deleteMachineDisruptionBudget(name
if err != nil {
return err
}
return r.updateClient.Delete(context.TODO(), mdb)
return r.client.Delete(context.TODO(), mdb)
}

func (r *ReconcileMachineRemediationOperator) getInfrastructure(name string) (*osconfigv1.Infrastructure, error) {
Expand Down
16 changes: 16 additions & 0 deletions pkg/utils/mapper/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["mapper.go"],
importpath = "kubevirt.io/machine-remediation-operator/pkg/utils/mapper",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/restmapper:go_default_library",
],
)
118 changes: 118 additions & 0 deletions pkg/utils/mapper/mapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package mapper

import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/discovery"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
)

// DynamicRESTMapper defines dynamic REST mapper entity
type DynamicRESTMapper struct {
client discovery.DiscoveryInterface
delegate meta.RESTMapper
}

// NewDynamicRESTMapper returns a RESTMapper that dynamically discovers resource
// types at runtime. This is in contrast to controller-manager's default RESTMapper, which
// only checks resource types at startup, and so can't handle the case of first creating a
// CRD and then creating an instance of that CRD.
func NewDynamicRESTMapper(cfg *rest.Config) (meta.RESTMapper, error) {
client, err := discovery.NewDiscoveryClientForConfig(cfg)
if err != nil {
return nil, err
}

drm := &DynamicRESTMapper{client: client}
if err := drm.reload(); err != nil {
return nil, err
}
return drm, nil
}

func (drm *DynamicRESTMapper) reload() error {
gr, err := restmapper.GetAPIGroupResources(drm.client)
if err != nil {
return err
}
drm.delegate = restmapper.NewDiscoveryRESTMapper(gr)
return nil
}

// reloadOnError checks if an error indicates that the delegated RESTMapper needs to be
// reloaded, and if so, reloads it and returns true.
func (drm *DynamicRESTMapper) reloadOnError(err error) bool {
if _, matches := err.(*meta.NoKindMatchError); !matches {
return false
}
err = drm.reload()
if err != nil {
utilruntime.HandleError(err)
}
return err == nil
}

// KindFor returns the kind by GroupVersionResource
func (drm *DynamicRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
gvk, err := drm.delegate.KindFor(resource)
if drm.reloadOnError(err) {
gvk, err = drm.delegate.KindFor(resource)
}
return gvk, err
}

// KindsFor returns kinds by GroupVersionResource
func (drm *DynamicRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
gvks, err := drm.delegate.KindsFor(resource)
if drm.reloadOnError(err) {
gvks, err = drm.delegate.KindsFor(resource)
}
return gvks, err
}

// ResourceFor returns resource by GroupVersionResource
func (drm *DynamicRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
gvr, err := drm.delegate.ResourceFor(input)
if drm.reloadOnError(err) {
gvr, err = drm.delegate.ResourceFor(input)
}
return gvr, err
}

// ResourcesFor returns resources by GroupVersionResource
func (drm *DynamicRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
gvrs, err := drm.delegate.ResourcesFor(input)
if drm.reloadOnError(err) {
gvrs, err = drm.delegate.ResourcesFor(input)
}
return gvrs, err
}

// RESTMapping returns RESTMapping from kind and versions
func (drm *DynamicRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
m, err := drm.delegate.RESTMapping(gk, versions...)
if drm.reloadOnError(err) {
m, err = drm.delegate.RESTMapping(gk, versions...)
}
return m, err
}

// RESTMappings returns RESTMappings from kind and versions
func (drm *DynamicRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
ms, err := drm.delegate.RESTMappings(gk, versions...)
if drm.reloadOnError(err) {
ms, err = drm.delegate.RESTMappings(gk, versions...)
}
return ms, err
}

// ResourceSingularizer returns resource singular
func (drm *DynamicRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
s, err := drm.delegate.ResourceSingularizer(resource)
if drm.reloadOnError(err) {
s, err = drm.delegate.ResourceSingularizer(resource)
}
return s, err
}

0 comments on commit aa31f4d

Please sign in to comment.