@@ -50,11 +50,13 @@ RESOURCE_OPTIONS = (
5050 "use_token_cache",
5151 "monitor_api",
5252 "device",
53+ "iflabel",
5354 "proxy",
5455)
5556IP_CMD = "/usr/sbin/ip"
57+ IFLABEL_MAX_LEN = 15 # Maximum character limit for interface labels
5658REQUESTS_TIMEOUT = 5 # Timeout for requests calls
57- HTTP_MAX_RETRIES = 3 # Maximum number of retries for HTTP requests
59+ HTTP_MAX_RETRIES = 4 # Maximum number of retries for HTTP requests
5860HTTP_BACKOFF_FACTOR = 0.3 # Sleep (factor * (2^number of previous retries)) secs
5961HTTP_STATUS_FORCE_RETRIES = (500, 502, 503, 504) # HTTP status codes to retry on
6062HTTP_RETRY_ALLOWED_METHODS = frozenset({"GET", "POST", "PUT", "DELETE"})
@@ -154,13 +156,13 @@ def ip_check_device(device):
154156 return False
155157
156158
157- def ip_alias_add(ip, device):
159+ def ip_alias_add(ip, device, label=None ):
158160 """Add an IP alias to the given device."""
159161 ip_cidr = f"{ip}/{CIDR_NETMASK}"
160162 ocf.logger.debug(
161- f"[ip_alias_add]: adding IP alias '{ip_cidr}' to interface '{device}'"
163+ f"[ip_alias_add]: adding IP alias '{ip_cidr}' with label '{label}' to interface '{device}'"
162164 )
163- _ = ip_address_add(ip_cidr, device)
165+ _ = ip_address_add(ip_cidr, device, label )
164166
165167
166168def ip_alias_remove(ip):
@@ -522,6 +524,7 @@ class PowerCloudRoute(PowerCloudAPI):
522524 region="",
523525 route_host_map="",
524526 device="",
527+ iflabel="",
525528 proxy="",
526529 monitor_api="",
527530 use_token_cache="",
@@ -543,6 +546,7 @@ class PowerCloudRoute(PowerCloudAPI):
543546 self.route_info = self._get_route_info()
544547 self.route_name = self.route_info["name"]
545548 self.device = self._get_device_name(device)
549+ self.iflabel = self._make_iflabel(iflabel)
546550
547551 def _get_ip_info(self, ip):
548552 """Validate the given IP address and return its standard form."""
@@ -588,7 +592,7 @@ class PowerCloudRoute(PowerCloudAPI):
588592 nodename = (
589593 hostname
590594 if not self._is_remote_route
591- else next((h for h in route_map if h != hostname), None)
595+ else next((host for host in route_map if host != hostname), None)
592596 )
593597
594598 if not nodename or nodename not in route_map:
@@ -646,6 +650,21 @@ class PowerCloudRoute(PowerCloudAPI):
646650 ocf.OCF_ERR_CONFIGURED,
647651 )
648652
653+ def _make_iflabel(self, label=None):
654+ """Constructs an interface label in the format 'device:label' if both are provided."""
655+ if not label or self._is_remote_route:
656+ return None
657+
658+ iflabel = f"{self.device}:{label}"
659+
660+ if len(iflabel) > IFLABEL_MAX_LEN:
661+ raise PowerCloudRouteError(
662+ f"_make_iflabel: interface label '{iflabel}' exceeds limit of {IFLABEL_MAX_LEN} characters",
663+ ocf.OCF_ERR_CONFIGURED,
664+ )
665+
666+ return iflabel
667+
649668 def _set_route_enabled(self, enabled: bool):
650669 """Enable or disable the PowerVS network route."""
651670 resource = f"/v1/routes/{self.route_id}"
@@ -706,6 +725,7 @@ def start_action(
706725 use_token_cache="",
707726 monitor_api="",
708727 device="",
728+ iflabel="",
709729 proxy="",
710730):
711731 """Assign the service IP.
@@ -730,7 +750,7 @@ def start_action(
730750 local_route = create_route_instance(resource_options)
731751
732752 # Add IP alias
733- ip_alias_add(ip, local_route.device)
753+ ip_alias_add(ip, local_route.device, local_route.iflabel )
734754
735755 # Enable local route
736756 ocf.logger.debug(f"[start_action]: enabling local route '{local_route.route_name}'")
@@ -758,6 +778,7 @@ def stop_action(
758778 use_token_cache="",
759779 monitor_api="",
760780 device="",
781+ iflabel="",
761782 proxy="",
762783):
763784 """Remove the service IP.
@@ -810,6 +831,7 @@ def monitor_action(
810831 use_token_cache="",
811832 monitor_api="",
812833 device="",
834+ iflabel="",
813835 proxy="",
814836):
815837 """Monitor the service IP.
@@ -829,15 +851,11 @@ def monitor_action(
829851 interface_name = ip_find_device(ip)
830852
831853 if not use_extended_monitor:
832- if interface_name:
833- ocf.logger.debug(
834- f"[monitor_action]: IP alias '{ip}' is active'"
835- )
854+ if interface_name:
855+ ocf.logger.debug(f"[monitor_action]: IP alias '{ip}' is active'")
836856 return ocf.OCF_SUCCESS
837- else:
838- ocf.logger.debug(
839- f"[monitor_action]: IP alias '{ip}' is not active"
840- )
857+ else:
858+ ocf.logger.debug(f"[monitor_action]: IP alias '{ip}' is not active")
841859 return ocf.OCF_NOT_RUNNING
842860
843861 remote_route = create_route_instance(
@@ -893,6 +911,7 @@ def validate_all_action(
893911 use_token_cache="",
894912 monitor_api="",
895913 device="",
914+ iflabel="",
896915 proxy="",
897916):
898917 """Validate resource agent parameters.
@@ -914,12 +933,10 @@ def main():
914933 Resource Agent to move an IP address from one Power Virtual Server instance to another.
915934
916935 Prerequisites:
917- 1. Red Hat Enterprise Linux 9.4 or higher
918-
919- 2. Two-node cluster
936+ 1. Two-node cluster
920937 - Distributed across two PowerVS workspaces in separate data centers within the same region.
921938
922- 3 . IBM Cloud API Key:
939+ 2 . IBM Cloud API Key:
923940 - Create a service API key with privileges for both workspaces.
924941 - Save the key in a file and copy it to both cluster nodes using the same path and filename.
925942 - Reference the key file path in the resource definition.
@@ -932,7 +949,7 @@ def main():
932949 "powervs-move-ip",
933950 shortdesc="Manages Power Virtual Server overlay IP routes.",
934951 longdesc=agent_description,
935- version=1.00 ,
952+ version=1.01 ,
936953 )
937954
938955 agent.add_parameter(
@@ -1011,6 +1028,17 @@ def main():
10111028 default="",
10121029 required=False,
10131030 )
1031+ agent.add_parameter(
1032+ "iflabel",
1033+ shortdesc="Network interface label",
1034+ longdesc=(
1035+ "A custom suffix for the IP address label. "
1036+ "It is appended to the interface name in the format device:label. "
1037+ "The full label must not exceed 15 characters. "
1038+ ),
1039+ content_type="string",
1040+ required=False,
1041+ )
10141042 agent.add_parameter(
10151043 "proxy",
10161044 shortdesc="Proxy",
0 commit comments