Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 93 additions & 18 deletions pkg/provisioner/ironic/ironic.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,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 @@ -321,6 +317,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,
}
Comment thread
s3rj1k marked this conversation as resolved.

pager := ports.List(p.client, opts)
Comment thread
s3rj1k marked this conversation as resolved.

allPages, err := pager.AllPages()
if err != nil {
return false, errors.Wrap(err, "failed to page over list of ports")
Comment thread
s3rj1k marked this conversation as resolved.
}

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 @@ -389,6 +429,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 @@ -475,18 +534,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 @@ -499,6 +549,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
}
}
}
}
Comment thread
s3rj1k marked this conversation as resolved.

// Look for the case where we previously enrolled this node
// and now the credentials have changed.
if credentialsChanged {
Expand Down Expand Up @@ -1611,9 +1689,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