337337 To replace an existing golden tag for a specific role:
338338 - **Unassign** the tag from the current role (e.g., `ACCESS`).
339339 - **Assign** the tag to the new role (e.g., `CORE`).
340- Idempotency Note:
341- - If an image is already tagged with 'ALL', requesting tagging for specific roles
342- (e.g., 'DISTRIBUTION,ACCESS') will result in no change (changed=0), because 'ALL'
343- is a superset that inherently includes all individual roles. The module checks the
344- golden tag status per role and recognizes that the requested roles are already covered.
340+ Idempotency (per-role check, Catalyst Center > 2.3.7.9):
341+ - Tagging is evaluated per role. If the image is already golden for 'ACCESS' and you
342+ request tagging for 'CORE', the module tags 'CORE' (changed=True). Previously this
343+ was silently skipped.
344+ - The module skips (changed=False) only when all requested roles are already tagged.
345+ - 'ALL' is treated as a superset: an image tagged with 'ALL' skips any subsequent
346+ request for one or more specific roles, since those roles are already covered.
347+ - For untagging, the module skips (changed=False) only when all requested roles are
348+ already untagged.
345349 Examples:
346350 - device_role: "ACCESS" tags only the `ACCESS` role as golden.
347351 - device_role: "ACCESS,CORE" tags both `ACCESS` and `CORE` roles as golden.
361365 Ordinal value.
362366 type: int
363367 tagging:
364- description: Boolean value to tag/untag
365- SWIM image as golden If True then the
366- given image will be tagged as golden.
367- If False then the given image will be
368- un-tagged as golden.
368+ description: Boolean value to tag/untag the
369+ SWIM image as golden. If True, the given
370+ image is tagged as golden. If False, the
371+ given image is un-tagged as golden.
369372 type: bool
370373 image_distribution_details:
371374 description: |
704707 - SDK Method used are
705708 software_image_management_swim.SoftwareImageManagementSwim.import_software_image_via_url,
706709 software_image_management_swim.SoftwareImageManagementSwim.tag_as_golden_image,
710+ software_image_management_swim.SoftwareImageManagementSwim.remove_golden_tag_for_image,
711+ software_image_management_swim.SoftwareImageManagementSwim.get_golden_tag_status_of_an_image,
712+ software_image_management_swim.SoftwareImageManagementSwim.tagging_golden_image,
713+ software_image_management_swim.SoftwareImageManagementSwim.untagging_golden_image,
714+ software_image_management_swim.SoftwareImageManagementSwim.returns_network_device_product_names_for_a_site,
707715 software_image_management_swim.SoftwareImageManagementSwim.trigger_software_image_distribution,
708716 software_image_management_swim.SoftwareImageManagementSwim.trigger_software_image_activation,
709717 software_image_management_swim.SoftwareImageManagementSwim.delete_image_v1,
710718
711719 - Paths used are
712720 post /dna/intent/api/v1/image/importation/source/url,
713721 post /dna/intent/api/v1/image/importation/golden,
722+ get /dna/intent/api/v1/image/importation/golden/site/{siteId}/family/{deviceFamilyIdentifier}/role/{deviceRole}/image/{imageId},
723+ post /dna/intent/api/v1/images/{id}/sites/{siteId}/tagGolden,
724+ post /dna/intent/api/v1/images/{id}/sites/{siteId}/untagGolden,
725+ get /dna/intent/api/v1/siteWiseProductNames,
714726 post /dna/intent/api/v1/image/distribution,
715727 post /dna/intent/api/v1/image/activation/device,
716728 delete /dna/intent/api/v1/images/{id},
@@ -2272,28 +2284,14 @@ def get_have(self):
22722284 ),
22732285 "INFO" ,
22742286 )
2275- (site_exists , site_id ) = self .site_exists ("Global" )
2276- if site_exists :
2277- have ["site_id" ] = site_id
2278- self .log (
2279- "Resolved Global site UUID for golden tagging workflow: {0}" .format (
2280- str (site_id )
2281- ),
2282- "INFO" ,
2283- )
2284- else :
2285- self .log (
2286- "Global site lookup did not return a valid site ID for Catalyst Center version {0}."
2287- " Golden tagging cannot continue without a real Global site UUID." .format (
2288- self .get_ccc_version ()
2289- ),
2290- "ERROR" ,
2291- )
2292- self .msg = "Unable to resolve the Global site ID in Cisco Catalyst Center for golden tagging."
2293- self .log (self .msg , "ERROR" )
2294- self .status = "failed"
2295- self .result ["response" ] = self .msg
2296- self .check_return_status ()
2287+ global_site_id = self .get_global_site_id ()
2288+ have ["site_id" ] = global_site_id
2289+ self .log (
2290+ "Resolved Global site UUID for golden tagging workflow: {0}" .format (
2291+ str (global_site_id )
2292+ ),
2293+ "INFO" ,
2294+ )
22972295
22982296 self .have .update (have )
22992297 # check if given device family name exists, store indentifier value
@@ -3396,11 +3394,35 @@ def get_diff_tagging(self):
33963394 api_response = response .get ("response" )
33973395 if api_response :
33983396 is_tagged = api_response .get ("taggedGolden" , False )
3397+ self .log (
3398+ "Golden tag status for role '{0}' is taggedGolden={1}" .format (
3399+ role , is_tagged
3400+ ),
3401+ "DEBUG" ,
3402+ )
33993403 if is_tagged :
3404+ self .log (
3405+ "SWIM Image '{0}' already tagged as Golden image in Cisco Catalyst Center for role '{1}'" .format (
3406+ image_name , role
3407+ ),
3408+ "INFO" ,
3409+ )
34003410 already_tagged_roles .add (role )
34013411 else :
3412+ self .log (
3413+ "SWIM Image '{0}' already un-tagged from Golden image in Cisco Catalyst Center for role '{1}'" .format (
3414+ image_name , role
3415+ ),
3416+ "INFO" ,
3417+ )
34023418 already_untagged_roles .add (role )
34033419 else :
3420+ self .log (
3421+ "No golden status response returned for role '{0}'. Assuming role is untagged." .format (
3422+ role
3423+ ),
3424+ "DEBUG" ,
3425+ )
34043426 already_untagged_roles .add (role )
34053427 except Exception as e :
34063428 self .log (
@@ -3422,12 +3444,6 @@ def get_diff_tagging(self):
34223444 if tag_image_golden :
34233445 # All desired roles are already tagged → idempotent skip
34243446 if desired_roles_set .issubset (already_tagged_roles ):
3425- self .log (
3426- "All requested roles {0} are already golden-tagged. Skipping as idempotent." .format (
3427- sorted (desired_roles_set )
3428- ),
3429- "DEBUG" ,
3430- )
34313447 self .msg = (
34323448 "SWIM Image '{0}' is already Golden tagged for device role(s) {1}. Skipping operation."
34333449 .format (image_name , role_display )
@@ -3437,12 +3453,6 @@ def get_diff_tagging(self):
34373453 else :
34383454 # All desired roles are already untagged → idempotent skip
34393455 if desired_roles_set .issubset (already_untagged_roles ):
3440- self .log (
3441- "All requested roles {0} are already not golden-tagged. Skipping untagging as idempotent." .format (
3442- sorted (desired_roles_set )
3443- ),
3444- "DEBUG" ,
3445- )
34463456 self .msg = (
34473457 "SWIM Image '{0}' is already not Golden tagged for device role(s) {1}. Skipping operation."
34483458 .format (image_name , role_display )
@@ -3513,7 +3523,7 @@ def get_diff_tagging(self):
35133523 op_modifies = True ,
35143524 params = {
35153525 "id" : image_id ,
3516- "site_id" : self .have .get ("site_id" ),
3526+ "site_id" : self .have .get ("site_id" ),
35173527 "payload" : payload
35183528 }
35193529 )
@@ -3536,14 +3546,10 @@ def get_diff_tagging(self):
35363546 device_family = tagging_details .get ("device_image_family_name" ) or "Unknown"
35373547
35383548 action = "Tagging" if tag_image_golden else "Un-Tagging"
3549+ display_roles = "ALL" if raw_roles .lower () == "all" else role_display
35393550 success_msg = (
3540- "{0} image {1} golden for site {2}, family {3}, device role(s) {4} successful."
3541- .format (
3542- action ,
3543- image_name ,
3544- site_name ,
3545- device_family ,
3546- "ALL" if raw_roles .lower () == "all" else ", " .join (sorted (desired_roles_set )) if desired_roles_set else "ALL" ,
3551+ "{0} image {1} golden for site {2}, family {3}, device role(s) {4} successful." .format (
3552+ action , image_name , site_name , device_family , display_roles
35473553 )
35483554 )
35493555
@@ -5474,6 +5480,18 @@ def verify_diff_tagged(self):
54745480 self .have .get ("site_id" ),
54755481 )
54765482 if product_name_ordinal is None :
5483+ self .log (
5484+ (
5485+ "Unable to verify golden tag status for image '{0}' because "
5486+ "product_name_ordinal could not be resolved for family '{1}' "
5487+ "at site_id '{2}'."
5488+ ).format (
5489+ image_name ,
5490+ tagging_details .get ("device_image_family_name" ),
5491+ self .have .get ("site_id" ),
5492+ ),
5493+ "WARNING" ,
5494+ )
54775495 return self
54785496
54795497 image_params = dict (
@@ -5510,20 +5528,14 @@ def verify_diff_tagged(self):
55105528 )
55115529
55125530 if image_status == tag_image_golden :
5513- if tag_image_golden :
5514- self .msg = """The requested image '{0}' has been tagged as golden in the Cisco Catalyst Center and
5515- its status has been successfully verified for device role(s) {1}.""" .format (
5516- image_name ,
5517- device_role ,
5518- )
5519- self .log (self .msg , "INFO" )
5520- else :
5521- self .msg = """The requested image '{0}' has been un-tagged as golden in the Cisco Catalyst Center and
5522- its status has been successfully verified for device role(s) {1}.""" .format (
5523- image_name ,
5524- device_role ,
5531+ tag_action = "tagged" if tag_image_golden else "un-tagged"
5532+ self .msg = (
5533+ "The requested image '{0}' has been {1} as golden in the Cisco Catalyst Center and "
5534+ "its status has been successfully verified for device role(s) {2}." .format (
5535+ image_name , tag_action , device_role
55255536 )
5526- self .log (self .msg , "INFO" )
5537+ )
5538+ self .log (self .msg , "INFO" )
55275539 else :
55285540 self .log (
55295541 """Mismatch between the playbook input for tagging/un-tagging image as golden and the Cisco Catalyst Center indicates that
@@ -5570,20 +5582,14 @@ def verify_diff_tagged(self):
55705582 "DEBUG" ,
55715583 )
55725584 if image_status == tag_image_golden :
5573- if tag_image_golden :
5574- self .msg = """The requested image '{0}' has been tagged as golden in the Cisco Catalyst Center and
5575- its status has been successfully verified for device role(s) {1}.""" .format (
5576- image_name ,
5577- device_role ,
5578- )
5579- self .log (self .msg , "INFO" )
5580- else :
5581- self .msg = """The requested image '{0}' has been un-tagged as golden in the Cisco Catalyst Center and
5582- image status has been verified for device role(s) {1}.""" .format (
5583- image_name ,
5584- device_role ,
5585+ tag_action = "tagged" if tag_image_golden else "un-tagged"
5586+ self .msg = (
5587+ "The requested image '{0}' has been {1} as golden in the Cisco Catalyst Center and "
5588+ "its status has been successfully verified for device role(s) {2}." .format (
5589+ image_name , tag_action , device_role
55855590 )
5586- self .log (self .msg , "INFO" )
5591+ )
5592+ self .log (self .msg , "INFO" )
55875593 else :
55885594 self .log (
55895595 """Mismatch between the playbook input for tagging/un-tagging image as golden and the Cisco Catalyst Center indicates that
0 commit comments