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

Commit

Permalink
using trait type instead of hardcode word 'trait' to create trait CR (#…
Browse files Browse the repository at this point in the history
…305)

* using trait type instead of hardcode word 'trait' to create trait CR

Fix #294

Signed-off-by: zzxwill <[email protected]>

* Use definition name or short name instead of kind for trait CR name

Signed-off-by: zzxwill <[email protected]>

* Use variable to remove reductant slice indexing

Signed-off-by: zzxwill <[email protected]>
  • Loading branch information
zzxwill authored Nov 21, 2020
1 parent a8ce94a commit 2cf8f63
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 33 deletions.
18 changes: 11 additions & 7 deletions pkg/controller/v1alpha2/applicationconfiguration/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/json"
"fmt"
"reflect"
"strings"

runtimev1alpha1 "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1"
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
Expand Down Expand Up @@ -210,18 +211,16 @@ func (r *components) renderTrait(ctx context.Context, ct v1alpha2.ComponentTrait
if err != nil {
return nil, nil, errors.Wrapf(err, errFmtRenderTrait, componentName)
}

traitName := getTraitName(ac, componentName, &ct, t)

setTraitProperties(t, traitName, ac.GetNamespace(), ref)

traitDef, err := util.FetchTraitDefinition(ctx, r.client, r.dm, t)
if err != nil {
if apierrors.IsNotFound(err) {
return t, util.GetDummyTraitDefinition(t), nil
}
return nil, nil, errors.Wrapf(err, errFmtGetTraitDefinition, t.GetAPIVersion(), t.GetKind(), t.GetName())
}
traitName := getTraitName(ac, componentName, &ct, t, traitDef)

setTraitProperties(t, traitName, ac.GetNamespace(), ref)

addDataOutputsToDAG(dag, ct.DataOutputs, t)

Expand Down Expand Up @@ -628,7 +627,7 @@ func checkConditions(conds []v1alpha2.ConditionRequirement, paved *fieldpath.Pav

// GetTraitName return trait name
func getTraitName(ac *v1alpha2.ApplicationConfiguration, componentName string,
ct *v1alpha2.ComponentTrait, t *unstructured.Unstructured) string {
ct *v1alpha2.ComponentTrait, t *unstructured.Unstructured, traitDef *v1alpha2.TraitDefinition) string {
var (
traitName string
apiVersion string
Expand All @@ -642,6 +641,11 @@ func getTraitName(ac *v1alpha2.ApplicationConfiguration, componentName string,
apiVersion = t.GetAPIVersion()
kind = t.GetKind()

traitType := traitDef.Name
if strings.Contains(traitType, ".") {
traitType = strings.Split(traitType, ".")[0]
}

for _, w := range ac.Status.Workloads {
if w.ComponentName != componentName {
continue
Expand All @@ -654,7 +658,7 @@ func getTraitName(ac *v1alpha2.ApplicationConfiguration, componentName string,
}

if len(traitName) == 0 {
traitName = util.GenTraitName(componentName, ct.DeepCopy())
traitName = util.GenTraitName(componentName, ct.DeepCopy(), traitType)
}

return traitName
Expand Down
189 changes: 176 additions & 13 deletions pkg/controller/v1alpha2/applicationconfiguration/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestRenderComponents(t *testing.T) {
errBoom := errors.New("boom")

namespace := "ns"
acName := "coolappconfig"
acName := "coolappconfig1"
acUID := types.UID("definitely-a-uuid")
componentName := "coolcomponent"
workloadName := "coolworkload"
Expand Down Expand Up @@ -759,7 +759,7 @@ func TestResolveParams(t *testing.T) {

func TestRenderTraitWithoutMetadataName(t *testing.T) {
namespace := "ns"
acName := "coolappconfig"
acName := "coolappconfig2"
acUID := types.UID("definitely-a-uuid")
componentName := "coolcomponent"
workloadName := "coolworkload"
Expand Down Expand Up @@ -848,8 +848,8 @@ func TestRenderTraitWithoutMetadataName(t *testing.T) {
t.Run(name, func(t *testing.T) {
r := &components{tc.fields.client, mock.NewMockDiscoveryMapper(), tc.fields.params, tc.fields.workload, tc.fields.trait}
got, _, _ := r.Render(tc.args.ctx, tc.args.ac)
if len(got) == 0 || len(got[0].Traits) == 0 || got[0].Traits[0].Object.GetName() != util.GenTraitName(componentName, ac.Spec.Components[0].Traits[0].DeepCopy()) {
t.Errorf("\n%s\nr.Render(...): -want error, +got error:\n%s\n", tc.reason, "Trait name is NOT"+
if len(got) == 0 || len(got[0].Traits) == 0 || got[0].Traits[0].Object.GetName() != util.GenTraitName(componentName, ac.Spec.Components[0].Traits[0].DeepCopy(), "") {
t.Errorf("\n%s\nr.Render(...): -want error, +got error:\n%s\n", tc.reason, "Trait name is NOT "+
"automatically set.")
}
})
Expand Down Expand Up @@ -1005,9 +1005,9 @@ func TestRenderTraitName(t *testing.T) {
assert.NoError(t, clientgoscheme.AddToScheme(scheme))
assert.NoError(t, core.AddToScheme(scheme))
namespace := "ns"
acName := "coolappconfig"
acName := "coolappconfig3"
acUID := types.UID("definitely-a-uuid")
componentName := "component"
componentName := "component3"

mts := v1alpha2.ManualScalerTrait{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -1019,8 +1019,9 @@ func TestRenderTraitName(t *testing.T) {
}

gvks, _, _ := scheme.ObjectKinds(&mts)
mts.APIVersion = gvks[0].GroupVersion().String()
mts.Kind = gvks[0].Kind
gvk := gvks[0]
mts.APIVersion = gvk.GroupVersion().String()
mts.Kind = gvk.Kind
raw, _ := json.Marshal(mts)

ac := &v1alpha2.ApplicationConfiguration{
Expand Down Expand Up @@ -1051,9 +1052,9 @@ func TestRenderTraitName(t *testing.T) {
Traits: []v1alpha2.WorkloadTrait{
{
Reference: v1alpha1.TypedReference{
APIVersion: gvks[0].GroupVersion().String(),
Kind: gvks[0].Kind,
Name: "component-trait-11111111",
APIVersion: gvk.GroupVersion().String(),
Kind: gvk.Kind,
Name: "component3-trait-11111111",
},
},
},
Expand All @@ -1066,8 +1067,170 @@ func TestRenderTraitName(t *testing.T) {
assert.NoError(t, err)
data := unstructured.Unstructured{Object: mapResult}

traitName := getTraitName(ac, componentName, &ac.Spec.Components[0].Traits[0], &data)
assert.Equal(t, traitName, "component-trait-11111111")
traitName := getTraitName(ac, componentName, &ac.Spec.Components[0].Traits[0], &data, &v1alpha2.TraitDefinition{})
assert.Equal(t, traitName, "component3-trait-11111111")
}

func TestRenderTraitNameWithoutReferenceName(t *testing.T) {
var scheme = runtime.NewScheme()
assert.NoError(t, clientgoscheme.AddToScheme(scheme))
assert.NoError(t, core.AddToScheme(scheme))
namespace := "ns"
acName := "coolappconfig4"
acUID := types.UID("definitely-a-uuid")
componentName := "component4"

mts := v1alpha2.ManualScalerTrait{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
},
Spec: v1alpha2.ManualScalerTraitSpec{
ReplicaCount: 3,
},
}

gvks, _, _ := scheme.ObjectKinds(&mts)
gvk := gvks[0]
mts.APIVersion = gvk.GroupVersion().String()
mts.Kind = gvk.Kind
raw, _ := json.Marshal(mts)

ac := &v1alpha2.ApplicationConfiguration{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: acName,
UID: acUID,
},
Spec: v1alpha2.ApplicationConfigurationSpec{
Components: []v1alpha2.ApplicationConfigurationComponent{
{
ComponentName: componentName,
Traits: []v1alpha2.ComponentTrait{
{
Trait: runtime.RawExtension{
Object: &mts,
Raw: raw,
},
},
},
},
},
},
Status: v1alpha2.ApplicationConfigurationStatus{
Workloads: []v1alpha2.WorkloadStatus{
{
ComponentName: componentName,
Traits: []v1alpha2.WorkloadTrait{
{
Reference: v1alpha1.TypedReference{
APIVersion: gvk.GroupVersion().String(),
Kind: gvk.Kind,
},
},
},
},
},
},
}

traitDef := v1alpha2.TraitDefinition{
TypeMeta: metav1.TypeMeta{
APIVersion: "core.oam.dev/v1alpha2",
Kind: "ManualScalerTrait",
},
ObjectMeta: metav1.ObjectMeta{
Name: "manualscalertraits.core.oam.dev",
},
}

mapResult, err := runtime.DefaultUnstructuredConverter.ToUnstructured(ac.Spec.Components[0].Traits[0].Trait.Object)
assert.NoError(t, err)
data := unstructured.Unstructured{Object: mapResult}

traitName := getTraitName(ac, componentName, &ac.Spec.Components[0].Traits[0], &data, &traitDef)
assert.Contains(t, traitName, "component4-manualscalertraits")
}

func TestRenderTraitNameWithShortNameTraitDefinition(t *testing.T) {
var scheme = runtime.NewScheme()
assert.NoError(t, clientgoscheme.AddToScheme(scheme))
assert.NoError(t, core.AddToScheme(scheme))
namespace := "ns"
acName := "coolappconfig5"
acUID := types.UID("definitely-a-uuid")
componentName := "component5"

mts := v1alpha2.ManualScalerTrait{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Labels: map[string]string{
oam.TraitTypeLabel: "scale",
},
},
Spec: v1alpha2.ManualScalerTraitSpec{
ReplicaCount: 3,
},
}

gvks, _, _ := scheme.ObjectKinds(&mts)
gvk := gvks[0]
mts.APIVersion = gvk.GroupVersion().String()
mts.Kind = gvk.Kind
raw, _ := json.Marshal(mts)

ac := &v1alpha2.ApplicationConfiguration{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: acName,
UID: acUID,
},
Spec: v1alpha2.ApplicationConfigurationSpec{
Components: []v1alpha2.ApplicationConfigurationComponent{
{
ComponentName: componentName,
Traits: []v1alpha2.ComponentTrait{
{
Trait: runtime.RawExtension{
Object: &mts,
Raw: raw,
},
},
},
},
},
},
Status: v1alpha2.ApplicationConfigurationStatus{
Workloads: []v1alpha2.WorkloadStatus{
{
ComponentName: componentName,
Traits: []v1alpha2.WorkloadTrait{
{
Reference: v1alpha1.TypedReference{
APIVersion: gvk.GroupVersion().String(),
Kind: gvk.Kind,
},
},
},
},
},
},
}

traitDef := v1alpha2.TraitDefinition{
TypeMeta: metav1.TypeMeta{
APIVersion: "core.oam.dev/v1alpha2",
Kind: "ManualScalerTrait",
},
ObjectMeta: metav1.ObjectMeta{
Name: "scale",
},
}
mapResult, err := runtime.DefaultUnstructuredConverter.ToUnstructured(ac.Spec.Components[0].Traits[0].Trait.Object)
assert.NoError(t, err)
data := unstructured.Unstructured{Object: mapResult}

traitName := getTraitName(ac, componentName, &ac.Spec.Components[0].Traits[0], &data, &traitDef)
assert.Contains(t, traitName, "component5-scale")
}

func TestMatchValue(t *testing.T) {
Expand Down
10 changes: 8 additions & 2 deletions pkg/oam/util/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"hash/fnv"
"os"
"reflect"
"strings"
"time"

"k8s.io/apimachinery/pkg/api/meta"
Expand Down Expand Up @@ -354,8 +355,13 @@ func Object2Map(obj interface{}) (map[string]interface{}, error) {
}

// GenTraitName generate trait name
func GenTraitName(componentName string, ct *v1alpha2.ComponentTrait) string {
return fmt.Sprintf("%s-%s-%s", componentName, TraitPrefixKey, ComputeHash(ct))
func GenTraitName(componentName string, ct *v1alpha2.ComponentTrait, traitType string) string {
var traitMiddleName = TraitPrefixKey
if traitType != "" {
traitMiddleName = strings.ToLower(traitType)
}
return fmt.Sprintf("%s-%s-%s", componentName, traitMiddleName, ComputeHash(ct))

}

// ComputeHash returns a hash value calculated from pod template and
Expand Down
48 changes: 37 additions & 11 deletions pkg/oam/util/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -805,16 +805,36 @@ func TestGenTraitName(t *testing.T) {
ReplicaCount: 3,
},
}
trait := v1alpha2.ManualScalerTrait{
TypeMeta: metav1.TypeMeta{
APIVersion: "extend.oam.dev/v1alpha2",
Kind: "ManualScalerTrait",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns",
Name: "sample-manualscaler-trait",
},
Spec: v1alpha2.ManualScalerTraitSpec{
ReplicaCount: 3,
},
}
traitTemplate := &v1alpha2.ComponentTrait{
Trait: runtime.RawExtension{
Object: &trait,
},
}

test := []struct {
name string
template *v1alpha2.ComponentTrait
exp string
tests := []struct {
name string
template *v1alpha2.ComponentTrait
definitionName string
exp string
}{
{
name: "simple",
template: &v1alpha2.ComponentTrait{},
exp: "simple-trait-67b8949f8d",
name: "simple",
template: &v1alpha2.ComponentTrait{},
definitionName: "",
exp: "simple-trait-67b8949f8d",
},
{
name: "simple",
Expand All @@ -823,12 +843,18 @@ func TestGenTraitName(t *testing.T) {
Object: &mts,
},
},
exp: "simple-trait-5ddc8b7556",
definitionName: "",
exp: "simple-trait-5ddc8b7556",
},
{
name: "simple-definition",
template: traitTemplate,
definitionName: "autoscale",
exp: "simple-definition-autoscale-" + util.ComputeHash(traitTemplate),
},
}
for _, test := range test {

got := util.GenTraitName(test.name, test.template)
for _, test := range tests {
got := util.GenTraitName(test.name, test.template, test.definitionName)
t.Log(fmt.Sprint("Running test: ", test.name))
assert.Equal(t, test.exp, got)
}
Expand Down

0 comments on commit 2cf8f63

Please sign in to comment.