Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add one SetFromTypedObject method to KubeObjectExt that allows to set all/any fields at once #142

Merged
merged 1 commit into from
May 4, 2023

Conversation

kispaljr
Copy link
Contributor

@kispaljr kispaljr commented Apr 28, 2023

Inspired by this comment from @johnbelamaric : this proposal adds a setter for the whole KubeObjectExt that allows to set all/any fields at once

@kispaljr kispaljr mentioned this pull request Apr 28, 2023
@kispaljr kispaljr requested a review from gvbalaji April 28, 2023 22:05
@kispaljr kispaljr changed the title Replace SetSpec and SetStatus with one SetFromTypedObject Add one SetFromTypedObject method to KubeObjectExt that allows to set all/any fields at once May 1, 2023
// SetFromTypedObject sets the value of `o` to `value`, while keeping most of the YAML formatting.
// It can be seen as an in-place version of fn.NewFromTypedObject
func (o *KubeObjectExt[T1]) SetFromTypedObject(value T1) error {
return safeSetNestedFieldKeepFormatting(&o.KubeObject, value)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am thinking instead of doing the following logic in the method safeSetNestedFieldKeepFormatting


if len(fields) == 0 {
		obj2, err := fn.NewFromTypedObject(value)
		if err != nil {
			return err
		}
		*obj = *obj

Can we create the new object(obj2) in this method only, convert it to value equivalent and pass it to safeSetNestedFieldKeepFormatting. That will keep that method consistent without any changes needed.

Does it make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass [the new object] to safeSetNestedFieldKeepFormatting

what would you put into the fields parameter, when you passing the new object?
In its current form if you call safeSetNestedFieldKeepFormatting without any fields parameter it will do nothing (this behavior is inherited from obj.SetNestedField that it calls internally.

Copy link

@gvbalaji gvbalaji May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well in SetFromTypedObject we will create the value for the passes in go struct and simply call
setNestedFieldKeepFormatting(obj, value) No fields passed i n.
Let SetNestedField take care of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately calling SetNestedField() with no fields at all is a noop: it doesn't return an error, but it doesn't do anything at all either.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isnt that what we want in this case as we are not passing any fields from SetFromTypedObject?

@henderiw
Copy link
Contributor

henderiw commented May 2, 2023

When testing this this does not work. When applying SetStatus it works fine.

func (r *fnCtx) updateIPAllocationResource(forObj *fn.KubeObject, objs fn.KubeObjects) (*fn.KubeObject, error) {
if forObj == nil {
return nil, fmt.Errorf("expected a for object but got nil")
}
fn.Logf("ipalloc: %v\n", forObj)
allocKOE, err := ko.NewFromKubeObject*ipamv1alpha1.IPAllocation
if err != nil {
return nil, err
}
alloc, err := allocKOE.GetGoStruct()
if err != nil {
return nil, err
}
resp, err := r.IpamClientProxy.Allocate(context.Background(), alloc, nil)
if err != nil {
return nil, err
}
alloc.Status = resp.Status

if alloc.Status.Prefix != nil {
	fn.Logf("ipalloc resp prefix: %v\n", *resp.Status.Prefix)
}
if alloc.Status.Gateway != nil {
	fn.Logf("ipalloc resp gateway: %v\n", *resp.Status.Gateway)
}
// set the status
//err = allocKOE.SetStatus(resp.Status)
err = allocKOE.SetFromTypedObject(resp)
return &allocKOE.KubeObject, err

}

testable using github.com/henderiw-nephio/pkg-examples -> ipam-fn

// the caller is responsible for ensuring that `obj` is not nil`
// SetFromTypedObject sets the value of `o` to `value`, while keeping most of the YAML formatting.
// It can be seen as an in-place version of fn.NewFromTypedObject
func (o *KubeObjectExt[T1]) SetFromTypedObject(value T1) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When testing this this does not work. When applying SetStatus it works fine.

func (r *fnCtx) updateIPAllocationResource(forObj *fn.KubeObject, objs fn.KubeObjects) (*fn.KubeObject, error) {
if forObj == nil {
return nil, fmt.Errorf("expected a for object but got nil")
}
fn.Logf("ipalloc: %v\n", forObj)
allocKOE, err := ko.NewFromKubeObject*ipamv1alpha1.IPAllocation
if err != nil {
return nil, err
}
alloc, err := allocKOE.GetGoStruct()
if err != nil {
return nil, err
}
resp, err := r.IpamClientProxy.Allocate(context.Background(), alloc, nil)
if err != nil {
return nil, err
}
alloc.Status = resp.Status

if alloc.Status.Prefix != nil {
fn.Logf("ipalloc resp prefix: %v\n", *resp.Status.Prefix)
}
if alloc.Status.Gateway != nil {
fn.Logf("ipalloc resp gateway: %v\n", *resp.Status.Gateway)
}
// set the status
//err = allocKOE.SetStatus(resp.Status)
err = allocKOE.SetFromTypedObject(resp)
return &allocKOE.KubeObject, err
}

testable using github.com/henderiw-nephio/pkg-examples -> ipam-fn

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the error message that you got?

For me the following testcase is green: (however see my next comment)

func TestIpalloc(t *testing.T) {
	var inputYaml string = `
apiVersion: ipam.alloc.nephio.org/v1alpha1
kind: IPAllocation
metadata:
  name: internetpool1
spec:
  kind: pool
  selector:
  matchLabels:
    nephio.org/site: edge1
  networkInstance: {}
  prefixLength: 8
`

	allocKOE, err := NewFromYaml[*ipamv1alpha1.IPAllocation]([]byte(inputYaml))
	assertNoError(t, err)
	alloc, err := allocKOE.GetGoStruct()
	assertNoError(t, err)

	alloc.Status.Gateway = "2.2.2.2"
	alloc.Status.AllocatedPrefix = "3.3.3.0"

	// set the status
	//err = allocKOE.SetStatus(resp.Status)
	err = allocKOE.SetFromTypedObject(alloc)
	assertNoError(t, err)

	var expectedYaml string = `apiVersion: ipam.alloc.nephio.org/v1alpha1
kind: IPAllocation
metadata:
  name: internetpool1
spec:
  kind: pool
  networkInstance: {}
  prefixLength: 8
status:
  prefix: 3.3.3.0
  gateway: 2.2.2.2`

	actualYaml := strings.TrimSpace(allocKOE.String())
	if actualYaml != expectedYaml {
		t.Errorf(actualYaml)
	}

}

Copy link
Contributor Author

@kispaljr kispaljr May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having said that you are using KubeObjectExt[*ipamv1alpha1.IPAllocation].
So far I thought that KubeObjectExt's type parameter should be a struct, as opposed to a pointer-to-struct. I came to this conclusion by looking into kubeobject_test.go (even the parts that wasn't written by me 🙂), and into the implementation of GetGoStruct():
GetGoStruct accidentally works with the pointer type parameter, but in that case we are passing a **ipamv1alpha1.IPAllocation to As(), while I think it was designed to receive a *ipamv1alpha1.IPAllocation.

This might also cause your different behavior between SetFromTypedObject and SetSpec. For SetSPec you pass resp.Status that is a struct, but to SetFromTypedObject() you pass resp that is a pointer-to-struct.

The important question here: Should we support pointer or struct type parameters?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@henderiw I've managed to run your github.com/henderiw-nephio/pkg-examples -> ipam-fn code,
and for me the SetStatus and SetFromTypedObject versions ouput the exact same result (character-by character).
What is your error?

@johnbelamaric
Copy link
Member

This LGTM, but has @henderiw 's issue been figured out?

@kispaljr
Copy link
Contributor Author

kispaljr commented May 4, 2023

This LGTM, but has @henderiw 's issue been figured out?

Yes. @henderiw, you confirmed to me that your tests are green now. Is that correct?

… KubeObjectExt from a go struct while keeping formatting
@ganchandrasekaran
Copy link
Contributor

/lgtm

@johnbelamaric
Copy link
Member

/approve

@nephio-prow
Copy link
Contributor

nephio-prow bot commented May 4, 2023

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: johnbelamaric

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@nephio-prow nephio-prow bot added the approved label May 4, 2023
@nephio-prow nephio-prow bot merged commit 3bb3a7f into nephio-project:main May 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants