-
Notifications
You must be signed in to change notification settings - Fork 56
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
Populate machine status with libvirt domain details #37
Conversation
/hold Still a WIP. Almost there. |
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.
Overall, looks good to me. Going to try it in the wild next.
dom, err := libvirtutils.LookupDomainByUUID(machine, uuid) | ||
if err != nil { | ||
glog.Errorf("Could not lookup created libvirt machine: %v", err) | ||
return fmt.Errorf("error looking up created machine %v", err) |
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.
Express which machine failed the lookup; ... %q ...", machine...
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.
Fixed.
|
||
if err := a.updateStatus(machine, dom); err != nil { | ||
glog.Errorf("Could not update machine status: %v", err) | ||
return fmt.Errorf("error updating machine status: %v", err) |
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.
Ditto regarding which machine; essentially avoid:
printf("could not open file")
in favour of:
printf("could not open %q: %v", filename, 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.
Fixed.
libvirtStatus, err := libvirtutils.ProviderStatus(machine) | ||
if err != nil { | ||
glog.Errorf("Could not get provider status for update: %v", err) | ||
return err |
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.
Why do we, in general, log errors, then return an err? Isn't the caller going to log the error, and perhaps with additional context?
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.
Mostly doing this in the "top-level" Update / Create / etc. methods because they are the boundary between the actuator and the upstream controller. I've run into cases where the controller didn't log the returned errors which caused a lot of wasted time debugging.
return nil, fmt.Errorf(LibVirtConIsNil) | ||
} | ||
|
||
dom, err := virConn.LookupDomainByUUID(uuid[:]) |
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.
Having got this far... I'm wondering why we pass a pointer to the uuid? Is it because it's an underlying C/native type?
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.
Nope, but it's represented as an array of 16 bytes, not a slice -- which is why it has to be sliced like this here. It seemed nicer to pass a pointer, especially in the case where the method might return an error and a nil UUID pointer rather than an error and a 16 byte array of zeros.
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.
Ended up dropping the UUID thing altogether and just looking up by name. It's simpler and should be fine.
|
||
status, ok := obj.(*providerconfigv1.LibvirtMachineProviderStatus) | ||
if !ok { | ||
return nil, fmt.Errorf("unexpected object: %#v", gvk) |
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.
Would expressing %T
be more useful here? i.e., what type did we get?
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.
This gvk
struct will have the group, version, and kind information. Honestly, this bit is just lifted from the AWS actuator, but it seems like a reasonable thing to log in this situation.
return "Shutoff" | ||
} | ||
|
||
return "Unknown" |
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.
Make this the default
case?
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.
Sure. Done.
/hold cancel |
I think this is ready. |
// object. | ||
func EncodeLibvirtMachineProviderStatus(status *providerconfigv1.LibvirtMachineProviderStatus) (*runtime.RawExtension, error) { | ||
// TODO: Modifying this in place feels weird. Should it be copied? | ||
status.TypeMeta = metav1.TypeMeta{ |
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.
You should not modify it. Weird you have to set the APIVersion and the Kind.
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.
This is what the AWS actuator does, but yeah, it felt weird. I don't think it's needed if we just set the metadata upfront when we first create a status, so I've done that instead and removed this bit.
return error.WithLog(err, "error getting provider status") | ||
} | ||
|
||
uuid, err := uuid.Parse(*libvirtStatus.InstanceID) |
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.
This panics when libvirtStatus.InstanceID
is nil
. In case you call the Update
from scratch without populating machine status.
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.
It should be fine to look based on domain name (to be define under cloud/libvirt/actuators/machine/utils/domain.go
):
func LookupDomainByName(machine *clusterv1.Machine) (*libvirt.Domain, error) {
machineProviderConfig, err := MachineProviderConfigFromClusterAPIMachineSpec(&machine.Spec)
client, err := buildClient(machineProviderConfig.URI)
if err != nil {
return nil, fmt.Errorf("Failed to build libvirt client: %s", err)
}
virConn := client.libvirt
if virConn == nil {
return nil, fmt.Errorf(LibVirtConIsNil)
}
dom, err := virConn.LookupDomainByName(machine.Name)
if err != nil {
return nil, fmt.Errorf("Failed to lookup domain by name: %v", err)
}
return dom, 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.
I ditched the whole UUID thing. It didn't make sense to look up the domain via a field stored in the status in order to update the status anyway. The domain is looked up by name now.
Just few nits, otherwise lgtm. I was able to apply the patch, build it and run it to collect machine status. Thanks @bison !!! |
@@ -62,11 +105,139 @@ func (a *Actuator) Delete(cluster *clusterv1.Cluster, machine *clusterv1.Machine | |||
// Update updates a machine and is invoked by the Machine Controller | |||
func (a *Actuator) Update(cluster *clusterv1.Cluster, machine *clusterv1.Machine) error { | |||
glog.Infof("Updating machine %v for cluster %v.", machine.Name, cluster.Name) | |||
return fmt.Errorf("TODO: Not yet implemented") | |||
error := errorWrapper{cluster: cluster, machine: machine} |
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.
Maybe errorWr
? I got confused by the error.WithLog
. The error
is allocated for error
type. We should not override it unless necessary.
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.
Good point. Fixed.
Dockerfile
Outdated
@@ -15,6 +15,8 @@ | |||
# Reproducible builder image | |||
FROM openshift/origin-release:golang-1.10 as builder | |||
|
|||
RUN yum install -y libvirt-devel |
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.
Do not add this as libvirt-devel
is already in openshift/origin-release:golang-1.10
image
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 like this was already fixed in master. This bit is gone after a rebase.
|
||
// UpdateProviderStatus updates the provider status in-place with info | ||
// from the given libvirt domain. | ||
func UpdateProviderStatus(status *providerconfigv1.LibvirtMachineProviderStatus, dom *libvirt.Domain) 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.
any machine api specific logic does not belong here, we can address it after merging and rebasing #38
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.
Fixed.
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.
Going to wait until this is re-based.
if name == "" { | ||
return fmt.Errorf("Failed to create domain, name is empty") | ||
return nil, fmt.Errorf("Failed to create domain, name is empty") |
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 think this is 'failed to create domain'. Rather, 'name is empty'. :-/
} | ||
|
||
// Get values from machineProviderConfig | ||
if err := domainDefInit(&domainDef, name, *machineProviderConfig); err != nil { | ||
return fmt.Errorf("Failed to init domain definition from machineProviderConfig: %v", err) | ||
return nil, fmt.Errorf("Failed to init domain definition from machineProviderConfig: %v", err) |
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.
We should consistently use %v
for error. In the few lines above we use %s
.
} | ||
} else { | ||
return fmt.Errorf("machine does not has a IgnKey value") | ||
return nil, fmt.Errorf("machine does not has a IgnKey value") |
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.
typo: machine does not _have_ a IgnKey value
.
Rebased and simplified this quite a bit. I think it's probably ready as-is, but a few open questions:
|
/approve |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: bison, ingvagabund, paulfantom 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 |
I vote we do that in a follow-up PR. Better to keep them small and easily reviewable (and revertable). |
This populates the machine's status subresource with the libvirt domain's details.