Skip to content
This repository has been archived by the owner on Jun 8, 2022. It is now read-only.

Commit

Permalink
Merge pull request #139 from ryanzhang-oss/move-to-helper
Browse files Browse the repository at this point in the history
move the workload ref get function to the common lib
  • Loading branch information
wonderflow authored Jul 27, 2020
2 parents 75ae2ae + 5380890 commit fd8856e
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

oamv1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
"github.com/crossplane/oam-kubernetes-runtime/pkg/oam"
"github.com/crossplane/oam-kubernetes-runtime/pkg/oam/util"
)

// Reconcile error strings.
const (
errLocateWorkload = "cannot find workload"
errFetchChildResources = "failed to fetch workload child resources"
errQueryOpenAPI = "failed to query openAPI"
errPatchTobeScaledResource = "cannot patch the resource for scale"
Expand Down Expand Up @@ -99,9 +97,9 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
eventObj = &manualScalar
}
// Fetch the workload instance this trait is referring to
workload, result, err := r.fetchWorkload(ctx, mLog, &manualScalar)
workload, result, err := util.FetchWorkload(ctx, r, mLog, &manualScalar)
if err != nil {
r.record.Event(eventObj, event.Warning(errLocateWorkload, err))
r.record.Event(eventObj, event.Warning(util.ErrLocateWorkload, err))
return result, err
}

Expand Down Expand Up @@ -129,31 +127,6 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
return ctrl.Result{}, util.PatchCondition(ctx, r, &manualScalar, cpv1alpha1.ReconcileSuccess())
}

// TODO (rz): this is actually pretty generic, we can move this out into a common Trait structure with client and log
func (r *Reconciler) fetchWorkload(ctx context.Context, mLog logr.Logger, oamTrait oam.Trait) (
*unstructured.Unstructured, ctrl.Result, error) {
var workload unstructured.Unstructured
workloadRef := oamTrait.GetWorkloadReference()
if len(workloadRef.Kind) == 0 || len(workloadRef.APIVersion) == 0 || len(workloadRef.Name) == 0 {
err := errors.New("no workload reference")
mLog.Error(err, errLocateWorkload)
return nil, util.ReconcileWaitResult,
util.PatchCondition(ctx, r, oamTrait, cpv1alpha1.ReconcileError(errors.Wrap(err, errLocateWorkload)))
}
workload.SetAPIVersion(workloadRef.APIVersion)
workload.SetKind(workloadRef.Kind)
wn := client.ObjectKey{Name: workloadRef.Name, Namespace: oamTrait.GetNamespace()}
if err := r.Get(ctx, wn, &workload); err != nil {
mLog.Error(err, "Workload not find", "kind", workloadRef.Kind, "workload name", workloadRef.Name)
return nil, util.ReconcileWaitResult,
util.PatchCondition(ctx, r, oamTrait, cpv1alpha1.ReconcileError(errors.Wrap(err, errLocateWorkload)))
}
mLog.Info("Get the workload the trait is pointing to", "workload name", workload.GetName(),
"workload APIVersion", workload.GetAPIVersion(), "workload Kind", workload.GetKind(), "workload UID",
workload.GetUID())
return &workload, ctrl.Result{}, nil
}

// identify child resources and scale them
func (r *Reconciler) scaleResources(ctx context.Context, mLog logr.Logger,
manualScalar oamv1alpha2.ManualScalerTrait, resources []*unstructured.Unstructured) (ctrl.Result, error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,146 +1,13 @@
package manualscalertrait

import (
"context"
"fmt"
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

runtimev1alpha1 "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1"
"github.com/crossplane/crossplane-runtime/pkg/test"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"

oamv1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
"github.com/crossplane/oam-kubernetes-runtime/pkg/oam/util"
)

func TestManualscalertrait(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Manualscalertrait Suite")
}

var _ = Describe("Manualscalar Trait Controller Test", func() {
BeforeEach(func() {
logf.Log.Info("Set up resources before a unit test")
})

AfterEach(func() {
logf.Log.Info("Clean up resources after a unit test")
})

It("Test fetch the workload the trait is reference to", func() {
By("Setting up variables")
log := ctrl.Log.WithName("ManualScalarTraitReconciler")
reconciler := &Reconciler{
log: log,
}
manualScalar := &oamv1alpha2.ManualScalerTrait{
TypeMeta: metav1.TypeMeta{
APIVersion: oamv1alpha2.SchemeGroupVersion.String(),
Kind: oamv1alpha2.ManualScalerTraitKind,
},
Spec: oamv1alpha2.ManualScalerTraitSpec{
ReplicaCount: 3,
WorkloadReference: runtimev1alpha1.TypedReference{
APIVersion: "apiversion",
Kind: "Kind",
Name: "wokload-example",
},
},
}
ctx := context.Background()
wl := oamv1alpha2.ContainerizedWorkload{
TypeMeta: metav1.TypeMeta{
APIVersion: oamv1alpha2.SchemeGroupVersion.String(),
Kind: oamv1alpha2.ContainerizedWorkloadKind,
},
}
uwl, _ := util.Object2Unstructured(wl)
workloadErr := fmt.Errorf("workload errr")
updateErr := fmt.Errorf("update errr")

type fields struct {
getFunc test.ObjectFn
patchStatusFunc test.MockStatusPatchFn
}
type want struct {
wl *unstructured.Unstructured
result ctrl.Result
err error
}
cases := map[string]struct {
fields fields
want want
}{
"FetchWorkload fails when getWorkload fails": {
fields: fields{
getFunc: func(obj runtime.Object) error {
return workloadErr
},
patchStatusFunc: func(_ context.Context, obj runtime.Object, patch client.Patch,
_ ...client.PatchOption) error {
return nil
},
},
want: want{
wl: nil,
result: util.ReconcileWaitResult,
err: nil,
},
},
"FetchWorkload fail and update fails when getWorkload fails": {
fields: fields{
getFunc: func(obj runtime.Object) error {
return workloadErr
},
patchStatusFunc: func(_ context.Context, obj runtime.Object, patch client.Patch,
_ ...client.PatchOption) error {
return updateErr
},
},
want: want{
wl: nil,
result: util.ReconcileWaitResult,
err: errors.Wrap(updateErr, util.ErrUpdateStatus),
},
},
"FetchWorkload succeeds when getWorkload succeeds": {
fields: fields{
getFunc: func(obj runtime.Object) error {
o, _ := obj.(*unstructured.Unstructured)
*o = *uwl
return nil
},
patchStatusFunc: func(_ context.Context, obj runtime.Object, patch client.Patch,
_ ...client.PatchOption) error {
return updateErr
},
},
want: want{
wl: uwl,
result: ctrl.Result{},
err: nil,
},
},
}
for name, tc := range cases {
tclient := test.NewMockClient()
tclient.MockGet = test.NewMockGetFn(nil, tc.fields.getFunc)
tclient.MockStatusPatch = tc.fields.patchStatusFunc
reconciler.Client = tclient
gotWL, result, err := reconciler.fetchWorkload(ctx, log, manualScalar)
By(fmt.Sprint("Running test: ", name))
Expect(tc.want.err).Should(util.BeEquivalentToError(err))
Expect(tc.want.wl).Should(Equal(gotWL))
Expect(tc.want.result).Should(Equal(result))
}
})
})
29 changes: 29 additions & 0 deletions pkg/oam/util/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"strings"
"time"

ctrl "sigs.k8s.io/controller-runtime"

cpv1alpha1 "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1"
"github.com/davecgh/go-spew/spew"
plur "github.com/gertd/go-pluralize"
Expand Down Expand Up @@ -46,6 +48,8 @@ const (
ErrUpdateStatus = "cannot apply status"
//ErrLocateAppConfig is the error while locating parent application.
ErrLocateAppConfig = "cannot locate the parent application configuration to emit event to"
// ErrLocateWorkload is the error while locate the workload
ErrLocateWorkload = "cannot find the workload that the trait is referencing to"
)

// A ConditionedObject is an Object type with condition field
Expand Down Expand Up @@ -78,6 +82,31 @@ func LocateParentAppConfig(ctx context.Context, client client.Client, oamObject
return nil, errors.Errorf(ErrLocateAppConfig)
}

// FetchWorkload fetch the workload that a trait is reference to
func FetchWorkload(ctx context.Context, c client.Client, mLog logr.Logger, oamTrait oam.Trait) (
*unstructured.Unstructured, ctrl.Result, error) {
var workload unstructured.Unstructured
workloadRef := oamTrait.GetWorkloadReference()
if len(workloadRef.Kind) == 0 || len(workloadRef.APIVersion) == 0 || len(workloadRef.Name) == 0 {
err := errors.New("no workload reference")
mLog.Error(err, ErrLocateWorkload)
return nil, ReconcileWaitResult,
PatchCondition(ctx, c, oamTrait, cpv1alpha1.ReconcileError(errors.Wrap(err, ErrLocateWorkload)))
}
workload.SetAPIVersion(workloadRef.APIVersion)
workload.SetKind(workloadRef.Kind)
wn := client.ObjectKey{Name: workloadRef.Name, Namespace: oamTrait.GetNamespace()}
if err := c.Get(ctx, wn, &workload); err != nil {
mLog.Error(err, "Workload not find", "kind", workloadRef.Kind, "workload name", workloadRef.Name)
return nil, ReconcileWaitResult,
PatchCondition(ctx, c, oamTrait, cpv1alpha1.ReconcileError(errors.Wrap(err, ErrLocateWorkload)))
}
mLog.Info("Get the workload the trait is pointing to", "workload name", workload.GetName(),
"workload APIVersion", workload.GetAPIVersion(), "workload Kind", workload.GetKind(), "workload UID",
workload.GetUID())
return &workload, ctrl.Result{}, nil
}

// FetchScopeDefinition fetch corresponding scopeDefinition given a scope
func FetchScopeDefinition(ctx context.Context, r client.Reader,
scope *unstructured.Unstructured) (*v1alpha2.ScopeDefinition, error) {
Expand Down
114 changes: 114 additions & 0 deletions pkg/oam/util/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,120 @@ var _ = Describe("Test LocateParentAppConfig helper utils", func() {
})
})

var _ = Describe(" Trait Controller Test", func() {
BeforeEach(func() {
logf.Log.Info("Set up resources before a unit test")
})

AfterEach(func() {
logf.Log.Info("Clean up resources after a unit test")
})

It("Test fetch the workload the trait is reference to", func() {
By("Setting up variables")
log := ctrl.Log.WithName("ManualScalarTraitReconciler")
manualScalar := &v1alpha2.ManualScalerTrait{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha2.SchemeGroupVersion.String(),
Kind: v1alpha2.ManualScalerTraitKind,
},
Spec: v1alpha2.ManualScalerTraitSpec{
ReplicaCount: 3,
WorkloadReference: v1alpha1.TypedReference{
APIVersion: "apiversion",
Kind: "Kind",
Name: "wokload-example",
},
},
}
ctx := context.Background()
wl := v1alpha2.ContainerizedWorkload{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha2.SchemeGroupVersion.String(),
Kind: v1alpha2.ContainerizedWorkloadKind,
},
}
uwl, _ := util.Object2Unstructured(wl)
workloadErr := fmt.Errorf("workload errr")
updateErr := fmt.Errorf("update errr")

type fields struct {
getFunc test.ObjectFn
patchStatusFunc test.MockStatusPatchFn
}
type want struct {
wl *unstructured.Unstructured
result ctrl.Result
err error
}
cases := map[string]struct {
fields fields
want want
}{
"FetchWorkload fails when getWorkload fails": {
fields: fields{
getFunc: func(obj runtime.Object) error {
return workloadErr
},
patchStatusFunc: func(_ context.Context, obj runtime.Object, patch client.Patch,
_ ...client.PatchOption) error {
return nil
},
},
want: want{
wl: nil,
result: util.ReconcileWaitResult,
err: nil,
},
},
"FetchWorkload fail and update fails when getWorkload fails": {
fields: fields{
getFunc: func(obj runtime.Object) error {
return workloadErr
},
patchStatusFunc: func(_ context.Context, obj runtime.Object, patch client.Patch,
_ ...client.PatchOption) error {
return updateErr
},
},
want: want{
wl: nil,
result: util.ReconcileWaitResult,
err: errors.Wrap(updateErr, util.ErrUpdateStatus),
},
},
"FetchWorkload succeeds when getWorkload succeeds": {
fields: fields{
getFunc: func(obj runtime.Object) error {
o, _ := obj.(*unstructured.Unstructured)
*o = *uwl
return nil
},
patchStatusFunc: func(_ context.Context, obj runtime.Object, patch client.Patch,
_ ...client.PatchOption) error {
return updateErr
},
},
want: want{
wl: uwl,
result: ctrl.Result{},
err: nil,
},
},
}
for name, tc := range cases {
tclient := test.NewMockClient()
tclient.MockGet = test.NewMockGetFn(nil, tc.fields.getFunc)
tclient.MockStatusPatch = tc.fields.patchStatusFunc
gotWL, result, err := util.FetchWorkload(ctx, tclient, log, manualScalar)
By(fmt.Sprint("Running test: ", name))
Expect(tc.want.err).Should(util.BeEquivalentToError(err))
Expect(tc.want.wl).Should(Equal(gotWL))
Expect(tc.want.result).Should(Equal(result))
}
})
})

var _ = Describe("Test scope related helper utils", func() {
ctx := context.Background()
namespace := "oamNS"
Expand Down

0 comments on commit fd8856e

Please sign in to comment.