@@ -343,13 +343,14 @@ def update_port_postcommit(self, context):
343343 'local_link_information' )
344344 if not local_link_information :
345345 return
346- switch_info = local_link_information [0 ].get ('switch_info' )
347- switch_id = local_link_information [0 ].get ('switch_id' )
348- switch = device_utils .get_switch_device (
349- self .switches , switch_info = switch_info ,
350- ngs_mac_address = switch_id )
351- if not switch :
352- return
346+ for link in local_link_information :
347+ switch_info = link .get ('switch_info' )
348+ switch_id = link .get ('switch_id' )
349+ switch = device_utils .get_switch_device (
350+ self .switches , switch_info = switch_info ,
351+ ngs_mac_address = switch_id )
352+ if not switch :
353+ return
353354 provisioning_blocks .provisioning_complete (
354355 context ._plugin_context , port ['id' ], resources .PORT ,
355356 GENERIC_SWITCH_ENTITY )
@@ -432,45 +433,86 @@ def bind_port(self, context):
432433 """
433434
434435 port = context .current
436+ network = context .network .current
435437 binding_profile = port ['binding:profile' ]
436438 local_link_information = binding_profile .get ('local_link_information' )
439+
437440 if self ._is_port_supported (port ) and local_link_information :
438- switch_info = local_link_information [0 ].get ('switch_info' )
439- switch_id = local_link_information [0 ].get ('switch_id' )
441+ # NOTE(jamesdenton): If any link of the port is invalid, none
442+ # of the links should be processed.
443+ if not self ._is_link_valid (port , network ):
444+ return
445+ else :
446+ for link in local_link_information :
447+ port_id = link .get ('port_id' )
448+ switch_info = link .get ('switch_info' )
449+ switch_id = link .get ('switch_id' )
450+ switch = device_utils .get_switch_device (
451+ self .switches , switch_info = switch_info ,
452+ ngs_mac_address = switch_id )
453+
454+ segments = context .segments_to_bind
455+ # If segmentation ID is None, set vlan 1
456+ segmentation_id = segments [0 ].get ('segmentation_id' ) or 1
457+ LOG .debug ("Putting port %(port_id)s on %(switch_info)s "
458+ "to vlan: %(segmentation_id)s" ,
459+ {'port_id' : port_id , 'switch_info' : switch_info ,
460+ 'segmentation_id' : segmentation_id })
461+ # Move port to network
462+ switch .plug_port_to_network (port_id , segmentation_id )
463+ LOG .info ("Successfully bound port %(port_id)s in segment "
464+ "%(segment_id)s on device %(device)s" ,
465+ {'port_id' : port ['id' ], 'device' : switch_info ,
466+ 'segment_id' : segmentation_id })
467+
468+ context .set_binding (segments [0 ][api .ID ],
469+ portbindings .VIF_TYPE_OTHER , {})
470+ provisioning_blocks .add_provisioning_component (
471+ context ._plugin_context , port ['id' ], resources .PORT ,
472+ GENERIC_SWITCH_ENTITY )
473+
474+ def _is_link_valid (self , port , network ):
475+ """Return whether a link references valid switch and physnet.
476+
477+ If the local link information refers to a switch that is not
478+ known to NGS or the switch is not associated with the respective
479+ physnet, the port will not be processed and no exception will
480+ be raised.
481+
482+ :param port: The port to check
483+ :param network: the network mapped to physnet
484+ :returns: Whether the link refers to a configured switch and/or switch
485+ is associated with physnet
486+ """
487+
488+ binding_profile = port ['binding:profile' ]
489+ local_link_information = binding_profile .get ('local_link_information' )
490+
491+ for link in local_link_information :
492+ switch_info = link .get ('switch_info' )
493+ switch_id = link .get ('switch_id' )
440494 switch = device_utils .get_switch_device (
441495 self .switches , switch_info = switch_info ,
442496 ngs_mac_address = switch_id )
443497 if not switch :
444- return
445- network = context .network .current
498+ LOG .error ("Cannot bind port %(port)s as device %(device)s "
499+ "is not configured. Check baremetal port link "
500+ "configuration." ,
501+ {'port' : port ['id' ],
502+ 'device' : switch_info })
503+ return False
504+
446505 physnet = network ['provider:physical_network' ]
447506 switch_physnets = switch ._get_physical_networks ()
507+
448508 if switch_physnets and physnet not in switch_physnets :
449- LOG .error ("Cannot bind port %(port)s as device %(device)s is "
450- "not on physical network %(physnet)" ,
451- {'port_id' : port ['id' ], 'device' : switch_info ,
509+ LOG .error ("Cannot bind port %(port)s as device %(device)s "
510+ "is not on physical network %(physnet)s. Check "
511+ "baremetal port link configuration." ,
512+ {'port' : port ['id' ], 'device' : switch_info ,
452513 'physnet' : physnet })
453- return
454- port_id = local_link_information [0 ].get ('port_id' )
455- segments = context .segments_to_bind
456- # If segmentation ID is None, set vlan 1
457- segmentation_id = segments [0 ].get ('segmentation_id' ) or 1
458- provisioning_blocks .add_provisioning_component (
459- context ._plugin_context , port ['id' ], resources .PORT ,
460- GENERIC_SWITCH_ENTITY )
461- LOG .debug ("Putting port {port} on {switch_info} to vlan: "
462- "{segmentation_id}" .format (
463- port = port_id ,
464- switch_info = switch_info ,
465- segmentation_id = segmentation_id ))
466- # Move port to network
467- switch .plug_port_to_network (port_id , segmentation_id )
468- LOG .info ("Successfully bound port %(port_id)s in segment "
469- "%(segment_id)s on device %(device)s" ,
470- {'port_id' : port ['id' ], 'device' : switch_info ,
471- 'segment_id' : segmentation_id })
472- context .set_binding (segments [0 ][api .ID ],
473- portbindings .VIF_TYPE_OTHER , {})
514+ return False
515+ return True
474516
475517 @staticmethod
476518 def _is_port_supported (port ):
@@ -513,34 +555,34 @@ def _unplug_port_from_network(self, port, network):
513555 local_link_information = binding_profile .get ('local_link_information' )
514556 if not local_link_information :
515557 return
516- switch_info = local_link_information [ 0 ]. get ( 'switch_info' )
517- switch_id = local_link_information [ 0 ] .get ('switch_id ' )
518- switch = device_utils . get_switch_device (
519- self . switches , switch_info = switch_info ,
520- ngs_mac_address = switch_id )
521- if not switch :
522- return
523- port_id = local_link_information [ 0 ]. get ( 'port_id' )
524- # If segmentation ID is None, set vlan 1
525- segmentation_id = network . get ( 'provider:segmentation_id' ) or 1
526- LOG . debug ( "Unplugging port {port} on {switch_info} from vlan: "
527- "{segmentation_id}" . format (
528- port = port_id ,
529- switch_info = switch_info ,
530- segmentation_id = segmentation_id ) )
531- try :
532- switch .delete_port (port_id , segmentation_id )
533- except Exception as e :
534- LOG .error ("Failed to unplug port %(port_id)s "
535- "on device: %(switch)s from network %(net_id)s "
536- "reason: %(exc)s" ,
537- {'port_id' : port ['id' ], 'net_id' : network ['id' ],
538- 'switch' : switch_info , 'exc' : e })
539- raise e
540- LOG .info ('Port %(port_id)s has been unplugged from network '
541- '%(net_id)s on device %(device)s' ,
542- {'port_id' : port ['id' ], 'net_id' : network ['id' ],
543- 'device' : switch_info })
558+ for link in local_link_information :
559+ switch_info = link .get ('switch_info ' )
560+ switch_id = link . get ( 'switch_id' )
561+ switch = device_utils . get_switch_device (
562+ self . switches , switch_info = switch_info ,
563+ ngs_mac_address = switch_id )
564+ if not switch :
565+ continue
566+ port_id = link . get ( 'port_id' )
567+ # If segmentation ID is None, set vlan 1
568+ segmentation_id = network . get ( 'provider:segmentation_id' ) or 1
569+ LOG . debug ( "Unplugging port %(port)s on %(switch_info)s from vlan: "
570+ "%(segmentation_id)s" ,
571+ { 'port' : port_id , ' switch_info' : switch_info ,
572+ ' segmentation_id' : segmentation_id } )
573+ try :
574+ switch .delete_port (port_id , segmentation_id )
575+ except Exception as e :
576+ LOG .error ("Failed to unplug port %(port_id)s "
577+ "on device: %(switch)s from network %(net_id)s "
578+ "reason: %(exc)s" ,
579+ {'port_id' : port ['id' ], 'net_id' : network ['id' ],
580+ 'switch' : switch_info , 'exc' : e })
581+ raise e
582+ LOG .info ('Port %(port_id)s has been unplugged from network '
583+ '%(net_id)s on device %(device)s' ,
584+ {'port_id' : port ['id' ], 'net_id' : network ['id' ],
585+ 'device' : switch_info })
544586
545587 def _get_devices_by_physnet (self , physnet ):
546588 """Generator yielding switches on a particular physical network.
0 commit comments