@@ -37,14 +37,10 @@ def register_tools(self, mcp: FastMCP):
3737 mcp .tool ()(self .get_port_detail )
3838 mcp .tool ()(self .update_port )
3939 mcp .tool ()(self .delete_port )
40- mcp .tool ()(self .add_port_fixed_ip )
41- mcp .tool ()(self .remove_port_fixed_ip )
40+
4241 mcp .tool ()(self .get_port_allowed_address_pairs )
43- mcp .tool ()(self .add_port_allowed_address_pair )
44- mcp .tool ()(self .remove_port_allowed_address_pair )
4542 mcp .tool ()(self .set_port_binding )
46- mcp .tool ()(self .set_port_admin_state )
47- mcp .tool ()(self .toggle_port_admin_state )
43+
4844 mcp .tool ()(self .get_floating_ips )
4945 mcp .tool ()(self .create_floating_ip )
5046 mcp .tool ()(self .attach_floating_ip_to_port )
@@ -430,63 +426,6 @@ def get_ports(
430426 ports = conn .list_ports (filters = filters )
431427 return [self ._convert_to_port_model (port ) for port in ports ]
432428
433- def add_port_fixed_ip (
434- self ,
435- port_id : str ,
436- subnet_id : str | None = None ,
437- ip_address : str | None = None ,
438- ) -> Port :
439- """
440- Add a fixed IP to a port.
441-
442- :param port_id: Target port ID
443- :param subnet_id: Subnet ID of the fixed IP entry
444- :param ip_address: Fixed IP address to add
445- :return: Updated Port object
446- """
447- conn = get_openstack_conn ()
448- port = conn .network .get_port (port_id )
449- fixed_ips = list (port .fixed_ips or [])
450- entry : dict = {}
451- if subnet_id is not None :
452- entry ["subnet_id" ] = subnet_id
453- if ip_address is not None :
454- entry ["ip_address" ] = ip_address
455- fixed_ips .append (entry )
456- updated = conn .network .update_port (port_id , fixed_ips = fixed_ips )
457- return self ._convert_to_port_model (updated )
458-
459- def remove_port_fixed_ip (
460- self ,
461- port_id : str ,
462- ip_address : str | None = None ,
463- subnet_id : str | None = None ,
464- ) -> Port :
465- """
466- Remove a fixed IP entry from a port.
467-
468- :param port_id: Target port ID
469- :param ip_address: Fixed IP address to remove
470- :param subnet_id: Subnet ID of the entry to remove
471- :return: Updated Port object
472- """
473- conn = get_openstack_conn ()
474- port = conn .network .get_port (port_id )
475- current = list (port .fixed_ips or [])
476- if not current :
477- return self ._convert_to_port_model (port )
478-
479- def predicate (item : dict ) -> bool :
480- if ip_address is not None and item .get ("ip_address" ) == ip_address :
481- return False
482- if subnet_id is not None and item .get ("subnet_id" ) == subnet_id :
483- return False
484- return True
485-
486- new_fixed = [fi for fi in current if predicate (fi )]
487- updated = conn .network .update_port (port_id , fixed_ips = new_fixed )
488- return self ._convert_to_port_model (updated )
489-
490429 def get_port_allowed_address_pairs (self , port_id : str ) -> list [dict ]:
491430 """
492431 Get allowed address pairs configured on a port.
@@ -498,68 +437,6 @@ def get_port_allowed_address_pairs(self, port_id: str) -> list[dict]:
498437 port = conn .network .get_port (port_id )
499438 return list (port .allowed_address_pairs or [])
500439
501- def add_port_allowed_address_pair (
502- self ,
503- port_id : str ,
504- ip_address : str ,
505- mac_address : str | None = None ,
506- ) -> Port :
507- """
508- Add an allowed address pair to a port.
509-
510- :param port_id: Port ID
511- :param ip_address: IP address to allow
512- :param mac_address: MAC address to allow
513- :return: Updated Port object
514- """
515- conn = get_openstack_conn ()
516- port = conn .network .get_port (port_id )
517-
518- pairs = list (port .allowed_address_pairs or [])
519- entry = {"ip_address" : ip_address }
520- if mac_address is not None :
521- entry ["mac_address" ] = mac_address
522- pairs .append (entry )
523-
524- updated = conn .network .update_port (
525- port_id ,
526- allowed_address_pairs = pairs ,
527- )
528- return self ._convert_to_port_model (updated )
529-
530- def remove_port_allowed_address_pair (
531- self ,
532- port_id : str ,
533- ip_address : str ,
534- mac_address : str | None = None ,
535- ) -> Port :
536- """
537- Remove an allowed address pair from a port.
538-
539- :param port_id: Port ID
540- :param ip_address: IP address to remove
541- :param mac_address: MAC address to remove. If not provided, remove all pairs with the IP
542- :return: Updated Port object
543- """
544- conn = get_openstack_conn ()
545- port = conn .network .get_port (port_id )
546- pairs = list (port .allowed_address_pairs or [])
547-
548- def keep (p : dict ) -> bool :
549- if mac_address is None :
550- return p .get ("ip_address" ) != ip_address
551- return not (
552- p .get ("ip_address" ) == ip_address
553- and p .get ("mac_address" ) == mac_address
554- )
555-
556- new_pairs = [p for p in pairs if keep (p )]
557- updated = conn .network .update_port (
558- port_id ,
559- allowed_address_pairs = new_pairs ,
560- )
561- return self ._convert_to_port_model (updated )
562-
563440 def set_port_binding (
564441 self ,
565442 port_id : str ,
@@ -590,40 +467,6 @@ def set_port_binding(
590467 updated = conn .network .update_port (port_id , ** update_args )
591468 return self ._convert_to_port_model (updated )
592469
593- def set_port_admin_state (
594- self ,
595- port_id : str ,
596- is_admin_state_up : bool ,
597- ) -> Port :
598- """
599- Set the administrative state of a port.
600-
601- :param port_id: Port ID
602- :param is_admin_state_up: Administrative state
603- :return: Updated Port object
604- """
605- conn = get_openstack_conn ()
606- updated = conn .network .update_port (
607- port_id ,
608- admin_state_up = is_admin_state_up ,
609- )
610- return self ._convert_to_port_model (updated )
611-
612- def toggle_port_admin_state (self , port_id : str ) -> Port :
613- """
614- Toggle the administrative state of a port.
615-
616- :param port_id: Port ID
617- :return: Updated Port object
618- """
619- conn = get_openstack_conn ()
620- current = conn .network .get_port (port_id )
621- updated = conn .network .update_port (
622- port_id ,
623- admin_state_up = not current .admin_state_up ,
624- )
625- return self ._convert_to_port_model (updated )
626-
627470 def create_port (
628471 self ,
629472 network_id : str ,
@@ -683,16 +526,37 @@ def update_port(
683526 is_admin_state_up : bool | None = None ,
684527 device_id : str | None = None ,
685528 security_group_ids : list [str ] | None = None ,
529+ allowed_address_pairs : list [dict ] | None = None ,
530+ fixed_ips : list [dict ] | None = None ,
686531 ) -> Port :
687532 """
688- Update an existing Port.
533+ Update an existing Port. Only provided parameters are changed; omitted parameters remain untouched.
534+
535+ Typical use-cases:
536+ - Set admin state down: is_admin_state_up=False
537+ - Toggle admin state: read current via get_port_detail() then pass the inverted value
538+ - Replace security groups: security_group_ids=["sg-1", "sg-2"]
539+ - Replace allowed address pairs:
540+ 1) current = get_port_allowed_address_pairs(port_id)
541+ 2) edit the list (append/remove dicts)
542+ 3) update_port(port_id, allowed_address_pairs=current)
543+ - Replace fixed IPs:
544+ 1) current = get_port_detail(port_id).fixed_ips
545+ 2) edit the list
546+ 3) update_port(port_id, fixed_ips=current)
547+
548+ Notes:
549+ - For list-typed fields like security groups or allowed address pairs, this method replaces
550+ the entire list with the provided value. To remove all entries, pass an empty list [].
689551
690552 :param port_id: ID of the port to update
691553 :param name: New port name
692554 :param description: New port description
693555 :param is_admin_state_up: Administrative state
694556 :param device_id: Device ID
695- :param security_group_ids: Security group ID list
557+ :param security_group_ids: Security group ID list (replaces entire list)
558+ :param allowed_address_pairs: Allowed address pairs (replaces entire list)
559+ :param fixed_ips: Fixed IP assignments (replaces entire list)
696560 :return: Updated Port object
697561 """
698562 conn = get_openstack_conn ()
@@ -707,6 +571,10 @@ def update_port(
707571 update_args ["device_id" ] = device_id
708572 if security_group_ids is not None :
709573 update_args ["security_groups" ] = security_group_ids
574+ if allowed_address_pairs is not None :
575+ update_args ["allowed_address_pairs" ] = allowed_address_pairs
576+ if fixed_ips is not None :
577+ update_args ["fixed_ips" ] = fixed_ips
710578 if not update_args :
711579 current = conn .network .get_port (port_id )
712580 return self ._convert_to_port_model (current )
0 commit comments