为GCP Compute实例设置标签时遇googleapiclient.errors.HttpError 412错误
问题场景
尝试使用以下Python代码为特定GCP Compute实例添加标签:
from pprint import pprint import googleapiclient.discovery compute = googleapiclient.discovery.build('compute', 'v1') projectid='XXXXXXXXX' zones=['australia-southeast1-b','australia-southeast1-a'] ip_list=[] instance_list=[] with open(r"D:\Users\xxxxxxxDesktop\Scripts\GCP\GCP-IP.txt") as f: for line in f: line = line.strip() ip_list.append(line) print(ip_list) for zo in zones: result = compute.instances().list(project=projectid, zone=zo).execute() for i in result['items']: for ip in ip_list: if i["networkInterfaces"][0]["networkIP"] == ip: instance_list.append({"ins_name" : i["name"], "fp" : i["tags"]["fingerprint"], "ins_zon":(i["zone"]).split("/")[-1]}) print(instance_list) for instance in instance_list: print(instance.get('fp')) instances_set_labels_request_body = { "labels": { "shutdown": "no" }, "LabelFingerprint":instance.get('fp') } request=compute.instances().setLabels(project=projectid, zone=instance.get('ins_zon'), instance=instance.get('ins_name'), body=instances_set_labels_request_body) response = request.execute()
错误信息
googleapiclient.errors.HttpError: <HttpError 412 when requesting https://compute.googleapis.com/compute/v1/projects/xxxxxxx/zones/australia-southeast1-b/instances/dxxxxxx/setLabels?alt=json returned "Labels fingerprint either invalid or resource labels have changed". Details: "[{'message': 'Labels fingerprint either invalid or resource labels have changed', 'domain': 'global', 'reason': 'conditionNotMet', 'location': 'If-Match', 'locationType': 'header'}]">
错误提示:标签指纹无效或资源标签已变更
解决方法
问题根源
代码提前批量收集了实例的标签指纹,但从获取指纹到执行setLabels操作的间隔中,目标实例的标签可能被其他操作(手动修改、其他脚本)修改,导致指纹失效;同时原代码请求体中的键名LabelFingerprint是错误的,正确应为小写开头的labelFingerprint,这也是验证失败的诱因。修正方案1:实时获取最新指纹再执行操作
不要提前缓存指纹,在准备设置标签前重新获取实例最新信息,拿到当前有效的标签指纹,同时修正请求体键名:for instance in instance_list: # 重新获取实例最新信息,拿到当前有效标签指纹 instance_detail = compute.instances().get( project=projectid, zone=instance.get('ins_zon'), instance=instance.get('ins_name') ).execute() # 优先取labels的指纹,没有则用tags的指纹 latest_fp = instance_detail.get('labels', {}).get('fingerprint', instance_detail['tags']['fingerprint']) # 若要保留原有标签,需合并原有标签和新标签,否则原有标签会被清空 updated_labels = instance_detail.get('labels', {}).copy() updated_labels['shutdown'] = 'no' instances_set_labels_request_body = { "labels": updated_labels, "labelFingerprint": latest_fp # 修正为正确的键名 } request = compute.instances().setLabels( project=projectid, zone=instance.get('ins_zon'), instance=instance.get('ins_name'), body=instances_set_labels_request_body ) response = request.execute()修正方案2:添加并发修改重试逻辑
如果存在多操作并发修改标签的场景,可添加重试机制,遇到412错误时重新获取指纹再尝试:from googleapiclient.errors import HttpError import time for instance in instance_list: max_retries = 3 retries = 0 success = False while retries < max_retries and not success: try: instance_detail = compute.instances().get( project=projectid, zone=instance.get('ins_zon'), instance=instance.get('ins_name') ).execute() latest_fp = instance_detail.get('labels', {}).get('fingerprint', instance_detail['tags']['fingerprint']) updated_labels = instance_detail.get('labels', {}).copy() updated_labels['shutdown'] = 'no' instances_set_labels_request_body = { "labels": updated_labels, "labelFingerprint": latest_fp } request = compute.instances().setLabels( project=projectid, zone=instance.get('ins_zon'), instance=instance.get('ins_name'), body=instances_set_labels_request_body ) response = request.execute() success = True print(f"实例 {instance.get('ins_name')} 标签设置成功") except HttpError as e: if e.resp.status == 412: retries += 1 print(f"实例 {instance.get('ins_name')} 指纹失效,重试第 {retries} 次") time.sleep(1) else: raise e if not success: print(f"实例 {instance.get('ins_name')} 标签设置失败,重试次数用尽")
内容的提问来源于stack exchange,提问作者Levun

