-
Notifications
You must be signed in to change notification settings - Fork 146
Added GetMetadata function to Machine #114
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
Conversation
machine.go
Outdated
| return nil, err | ||
| } | ||
|
|
||
| payload, ok := resp.Payload.(map[string]interface{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if I like defaulting to map[string]interface{} as []interface{} seems just as feasible. I think we need to think about this a little more, maybe use reflection to unmarshal into a structure may be nice.
func(m *Machine) GetMetadata(ctx context.Context, v interface{}) error {
// TODO: use reflection here
}How do you feel about just updating the client for now and removing the machine GetMetadata and adding an issue asking for a higher level abstraction? Or if you prefer to implement the reflection portion, that'd be very helpful :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about reflection too, I wasn't sure if you guys wanted all that code inside of the sdk. I don't think it'll be too bad since the MMDs only allows strings, objects, and arrays of strings.
I assume for the reflection we would just unmarshal off of the json struct tags?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cpheps - Yea, using json tags is the way to go, and I think this creates a much better interface for users to be able to have the SDK do the unmarshaling for them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I'll go down that path. I also noticed the Patch MMDs was not hooked up to the machine, that seems fairly straight forward and I need that functionality so I'm going to throw that onto this PR.
|
@xibz Added reflection unmarshaling to GetMmds and hooked up the PATCH MMDs to the machine. |
machine.go
Outdated
| } | ||
|
|
||
| m.logger.Printf("GetMetadata successful") | ||
| return unmarshalMetadata(resp.Payload, v) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we just use json.Unmarshal here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha, hadn't thought of that. Yes, as long as we can turn resp.Payload into a []byte. I'm not quite sure how to do that, I found this example
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err = enc.Encode(resp.Payload)
if err != nil {
return err
}
return json.Unmarshal(buf.Bytes(), v)but it returns an error during unmarshal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Best I can come up with is to json.Marshal(resp.Payload) then feed those bytes into the json.Unmarshal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's probably the best approach for now. The response is unmarshalled into an interface{} by the runtime.JSONConsumer and the godoc for json.Unmarshal says this:
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
We don't actually know which type will end up in the resp.Payload field and would have to deal with that. Since we expect that the MMDS will contain JSON (that's the documented use), and since json.Unmarshal and json.Marshal (intend to) have inverse encodings, I think it's reasonable to let them operate together rather than rewriting it ourselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is difficult primarily because the get operation's return value is defined as object in the Swagger spec, and that gets converted into interface{} in our client. If it were a string in the Swagger spec, we could either get a string or []byte back from the client, and then apply our own deserialization instead of one of these approaches.
I've opened firecracker-microvm/firecracker#1229 to discuss that possibility with the Firecracker team.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not apposed to doing the json.Marshal into a json.Unmarshal. The reason I hand rolled the unmarshaling is the set of possible JSON that could be put into MMDS seemed limited. I could be wrong but seems like the top level object is either an array or json object that will eventual cascade down into a string value.
The json package will do this fine, and I don't think there is any danger of getting a non-string value out since we have to process something coming out of the MMDS.
I'll keep the custom code for now but let me know if we want to switch to the json package, it's easy enough to swap out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@samuelkarp Thanks for the submission to the Firecracker team. One note I would add is currently the swagger is incorrect. It says object but it could also return an array of strings or objects. The swagger overall is a bit misleading if you aren't familiar with using MMDS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My preference would be to switch to the json package, as then there's less code for us to test and maintain over time.
I could be wrong but seems like the top level object is either an array or json object that will eventual cascade down into a string value.
MMDS currently accepts strings, dictionaries, and objects at the top level, but I'd prefer not to have to know that (and maintain code that knows that).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@samuelkarp Works for me, just pushed the update.
kzys
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
machine.go
Outdated
|
|
||
| // GetMetadata gets the machine's metadata from MDDS and unmarshals it into v | ||
| func (m *Machine) GetMetadata(ctx context.Context, v interface{}) error { | ||
| if v == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor comment is that we probably don't need to check for nil here as json.Unmarshal seems to behave fine and does not return an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh good call, left over artifact. I'll remove that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also clean up the commits into a single commit and ensure the author is correct? If you take a look at the current commits only one of them actually references you.
xibz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! Thanks @cpheps for the contribution :D
samuelkarp
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @cpheps! The code looks good to me, but would you be able to squash this all into a single commit? If not, we can take care of that when we merge it.
Added test for GetMetadata on machine Fixed some spelling issues and actually put test for GetMetadata Added MMDs PATCH and GET reflection (#1) Hooked up machine function for PATCH Mmds and added reflection unmarshaling for GetMmds Replaced custom marshaling for using the json package in GetMmds Removed extra nil check in GetMetadata
|
@samuelkarp Sqashed all the commits. |
|
@samuelkarp Do you know if you guys are waiting for a resolution on firecracker-microvm/firecracker#1229 before merging? We're currently using my fork in production but would like to get back to the actual library just wondering on the timeline. |
samuelkarp
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @cpheps! My apologies for the delay; I had intended to merge this yesterday but ran out of time.
I'll be merging this with a rewritten commit message, so the PR may not show up as "Merged" but the code will be (and your email address will still be credited as the author).
Issue #, if available:
Resolves #109
Description of changes:
Added a function
GetMetadatafunction to the Machine to wrap theGetMmdsof client. I had the function return amap[string]interface{}, I figured this was the path of least resistance to return the meta data and allow the caller to parse it.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.