diff --git a/pkg/cloud/openstack/clients/machineservice.go b/pkg/cloud/openstack/clients/machineservice.go index ecf910f630..a66d944fbb 100644 --- a/pkg/cloud/openstack/clients/machineservice.go +++ b/pkg/cloud/openstack/clients/machineservice.go @@ -33,6 +33,7 @@ import ( "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume" "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips" "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs" + "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors" "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images" @@ -60,6 +61,15 @@ const ( TimeoutPortDelete = 3 * time.Minute RetryIntervalPortDelete = 5 * time.Second + + // MachineRegionLabelName as annotation name for a machine region + MachineRegionLabelName = "machine.openshift.io/region" + + // MachineAZLabelName as annotation name for a machine AZ + MachineAZLabelName = "machine.openshift.io/zone" + + // MachineInstanceTypeLabelName as annotation name for a machine instance type + MachineInstanceTypeLabelName = "machine.openshift.io/instance-type" ) type InstanceService struct { @@ -68,6 +78,8 @@ type InstanceService struct { identityClient *gophercloud.ServiceClient networkClient *gophercloud.ServiceClient imagesClient *gophercloud.ServiceClient + + regionName string } type Instance struct { @@ -92,6 +104,19 @@ type InstanceListOpts struct { Name string `q:"name"` } +type serverMetadata struct { + // AZ contains name of the server's availability zone + AZ string `json:"OS-EXT-AZ:availability_zone"` + + // Flavor refers to a JSON object, which itself indicates the hardware + // configuration of the deployed server. + Flavor map[string]interface{} `json:"flavor"` + + // Status contains the current operational status of the server, + // such as IN_PROGRESS or ACTIVE. + Status string `json:"status"` +} + func GetCloudFromSecret(kubeClient kubernetes.Interface, namespace string, secretName string, cloudName string) (clientconfig.Cloud, error) { emptyCloud := clientconfig.Cloud{} @@ -205,6 +230,7 @@ func NewInstanceServiceFromCloud(cloud clientconfig.Cloud) (*InstanceService, er computeClient: serverClient, networkClient: networkingClient, imagesClient: imagesClient, + regionName: clientOpts.RegionName, }, nil } @@ -729,6 +755,38 @@ func (is *InstanceService) GetInstance(resourceId string) (instance *Instance, e return serverToInstance(server), err } +// SetMachineLabels set labels describing the machine +func (is *InstanceService) SetMachineLabels(machine *machinev1.Machine, instanceID string) error { + if machine.Labels[MachineRegionLabelName] != "" && machine.Labels[MachineAZLabelName] != "" && machine.Labels[MachineInstanceTypeLabelName] != "" { + return nil + } + + var sm serverMetadata + err := servers.Get(is.computeClient, instanceID).ExtractInto(&sm) + if err != nil { + return err + } + + if machine.Labels == nil { + machine.Labels = make(map[string]string) + } + + // Set the region + machine.Labels[MachineRegionLabelName] = is.regionName + + // Set the availability zone + machine.Labels[MachineAZLabelName] = sm.AZ + + // Set the flavor name + flavor, err := flavors.Get(is.computeClient, sm.Flavor["id"].(string)).Extract() + if err != nil { + return err + } + machine.Labels[MachineInstanceTypeLabelName] = flavor.Name + + return nil +} + func serverToInstance(server *servers.Server) *Instance { return &Instance{*server} } diff --git a/pkg/cloud/openstack/machine/actuator.go b/pkg/cloud/openstack/machine/actuator.go index 7361e8000e..1a33a086de 100644 --- a/pkg/cloud/openstack/machine/actuator.go +++ b/pkg/cloud/openstack/machine/actuator.go @@ -58,6 +58,9 @@ const ( TimeoutInstanceCreate = 5 TimeoutInstanceDelete = 5 RetryIntervalInstanceStatus = 10 * time.Second + + // MachineInstanceStateAnnotationName as annotation name for a machine instance state + MachineInstanceStateAnnotationName = "machine.openshift.io/instance-state" ) type OpenstackClient struct { @@ -244,6 +247,11 @@ func (oc *OpenstackClient) Create(ctx context.Context, cluster *clusterv1.Cluste } + err = machineService.SetMachineLabels(machine, instance.ID) + if err != nil { + return nil + } + return oc.updateAnnotation(machine, instance.ID) } @@ -287,6 +295,18 @@ func (oc *OpenstackClient) Update(ctx context.Context, cluster *clusterv1.Cluste } if instance != nil && instance.Status == "ACTIVE" { klog.Infof("Populating current state for boostrap machine %v", machine.ObjectMeta.Name) + + kubeClient := oc.params.KubeClient + machineService, err := clients.NewInstanceServiceFromMachine(kubeClient, machine) + if err != nil { + return err + } + + err = machineService.SetMachineLabels(machine, instance.ID) + if err != nil { + return nil + } + return oc.updateAnnotation(machine, instance.ID) } else { return fmt.Errorf("Cannot retrieve current state to update machine %v", machine.ObjectMeta.Name) @@ -406,6 +426,8 @@ func (oc *OpenstackClient) updateAnnotation(machine *machinev1.Machine, id strin return err } machine.ObjectMeta.Annotations[openstack.OpenstackIPAnnotationKey] = ip + machine.ObjectMeta.Annotations[MachineInstanceStateAnnotationName] = instance.Status + if err := oc.client.Update(nil, machine); err != nil { return err }