Skip to content

Commit

Permalink
Merge pull request #817 from s3rj1k/IRONIC_PORT
Browse files Browse the repository at this point in the history
Allocate Ironic port when node exists and has no port allocated.
  • Loading branch information
metal3-io-bot committed May 10, 2021
2 parents fa1773f + 291eb95 commit a3c360b
Showing 1 changed file with 93 additions and 18 deletions.
111 changes: 93 additions & 18 deletions pkg/provisioner/ironic/ironic.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,6 @@ func (p *ironicProvisioner) listAllPorts(address string) ([]ports.Port, error) {

pager := ports.List(p.client, opts)

if pager.Err != nil {
return allPorts, pager.Err
}

allPages, err := pager.AllPages()

if err != nil {
Expand Down Expand Up @@ -342,6 +338,50 @@ func (p *ironicProvisioner) getNode() (*nodes.Node, error) {
}
}

// Verifies that node has port assigned by Ironic.
func (p *ironicProvisioner) nodeHasAssignedPort(ironicNode *nodes.Node) (bool, error) {
opts := ports.ListOpts{
Fields: []string{"node_uuid"},
NodeUUID: ironicNode.UUID,
}

pager := ports.List(p.client, opts)

allPages, err := pager.AllPages()
if err != nil {
return false, errors.Wrap(err, "failed to page over list of ports")
}

empty, err := allPages.IsEmpty()
if err != nil {
return false, errors.Wrap(err, "failed to check port list status")
}

if empty {
p.debugLog.Info("node has no assigned port")
return false, nil
}

p.debugLog.Info("node has assigned port")
return true, nil
}

// Verify that MAC is already allocated to some node port.
func (p *ironicProvisioner) isAddressAllocatedToPort(address string) (bool, error) {
allPorts, err := p.listAllPorts(address)
if err != nil {
return false, errors.Wrap(err, fmt.Sprintf("failed to list ports for %s", address))
}

if len(allPorts) == 0 {
p.debugLog.Info("address does not have allocated ports", "address", address)
return false, nil
}

p.debugLog.Info("address is allocated to port", "address", address)
return true, nil
}

// Look for an existing registration for the host in Ironic.
func (p *ironicProvisioner) findExistingHost(bootMACAddress string) (ironicNode *nodes.Node, err error) {
// Try to load the node by UUID
Expand Down Expand Up @@ -410,6 +450,25 @@ func (p *ironicProvisioner) findExistingHost(bootMACAddress string) (ironicNode
return nil, nil
}

func (p *ironicProvisioner) createPXEEnabledNodePort(uuid, macAddress string) error {
p.log.Info("creating PXE enabled ironic port for node", "NodeUUID", uuid, "MAC", macAddress)

enable := true

_, err := ports.Create(
p.client,
ports.CreateOpts{
NodeUUID: uuid,
Address: macAddress,
PXEEnabled: &enable,
}).Extract()
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to create ironic port for node: %s, MAC: %s", uuid, macAddress))
}

return nil
}

// ValidateManagementAccess registers the host with the provisioning
// system and tests the connection information for the host to verify
// that the location and credentials work.
Expand Down Expand Up @@ -496,18 +555,9 @@ func (p *ironicProvisioner) ValidateManagementAccess(data provisioner.Management
// If we know the MAC, create a port. Otherwise we will have
// to do this after we run the introspection step.
if p.bootMACAddress != "" {
enable := true
p.log.Info("creating port for node in ironic", "MAC",
p.bootMACAddress)
_, err = ports.Create(
p.client,
ports.CreateOpts{
NodeUUID: ironicNode.UUID,
Address: p.bootMACAddress,
PXEEnabled: &enable,
}).Extract()
err = p.createPXEEnabledNodePort(ironicNode.UUID, p.bootMACAddress)
if err != nil {
result, err = transientError(errors.Wrap(err, "failed to create port in ironic"))
result, err = transientError(err)
return
}
}
Expand All @@ -520,6 +570,34 @@ func (p *ironicProvisioner) ValidateManagementAccess(data provisioner.Management

updater.SetTopLevelOpt("name", ironicNodeName(p.objectMeta), ironicNode.Name)

// When node exists but has no assigned port to it by Ironic and actuall address (MAC) is present
// in host config and is not allocated to different node lets try to create port for this node.
if p.bootMACAddress != "" {
var nodeHasAssignedPort, addressIsAllocatedToPort bool

nodeHasAssignedPort, err = p.nodeHasAssignedPort(ironicNode)
if err != nil {
result, err = transientError(err)
return
}

if !nodeHasAssignedPort {
addressIsAllocatedToPort, err = p.isAddressAllocatedToPort(p.bootMACAddress)
if err != nil {
result, err = transientError(err)
return
}

if !addressIsAllocatedToPort {
err = p.createPXEEnabledNodePort(ironicNode.UUID, p.bootMACAddress)
if err != nil {
result, err = transientError(err)
return
}
}
}
}

// Look for the case where we previously enrolled this node
// and now the credentials have changed.
if credentialsChanged {
Expand Down Expand Up @@ -1632,9 +1710,6 @@ func (p *ironicProvisioner) loadBusyHosts() (hosts map[string]struct{}, err erro
pager := nodes.List(p.client, nodes.ListOpts{
Fields: []string{"uuid,name,provision_state,driver_internal_info,target_provision_state"},
})
if pager.Err != nil {
return nil, pager.Err
}

page, err := pager.AllPages()
if err != nil {
Expand Down

0 comments on commit a3c360b

Please sign in to comment.