是否存在一些已知问题,即 Azure Runbooks 的 Python 环境不喜欢将
while
循环函数与 print
函数结合使用而不附加 flush=True
?
当
while
一词包含在 main
函数中时,我没有看到返回任何打印语句。
这旨在每当我的 Azure VM 的状态发生变化时发送警报。 (这将通过电子邮件进行,但为了方便起见,我刚刚包含了打印语句......这应该有效)
删除
while
功能,所有打印语句都会出现。
这是一个非常愚蠢的情况。即使
print("Can you see this message....")
和 print("Entering loop...")
也不会打印。这些 print
语句甚至不会在 while
循环中打印,因此即使 while
循环的执行存在问题(实际上不存在),它也应该打印。我会通过调试打印向您展示,但如果实际打印的内容像我告诉的那样,那么您就可以看到。
我的血压因此而严重升高。
compute_client
已通过身份验证,并且它返回正确的 vm_name
,那么为什么 - 每当我包含 while
循环时 - 它是否有嘶嘶声?
我对此非常生气。
import time, random, smtplib, inspect, string
from datetime import datetime
from email.mime.text import MIMEText
from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.compute import ComputeManagementClient
# Azure setup
subscription_id = 'xxx'
resource_group_name = 'xxx'
vm_name = 'xxx'
from azure.core.exceptions import ClientAuthenticationError
# Authentication of Azure's Service Principal
def service_principal_authentication():
"""Checks the Authentication of Azure's Service Principal """
print("Authenticating Service Principal....")
try:
credentials = ServicePrincipalCredentials(
client_id='xxx',
secret='xxx',
tenant='xxx'
)
print("Service Principal Authenticity Verified")
return ComputeManagementClient(credentials, subscription_id)
except Exception as e:
print(f"There was an error with the authenticating the Service Principal: {e}")
except ClientAuthenticationError as e:
print(f"Client Authentication Error {e}")
# Email setup
sender_email = 'xxx'
receiver_email = 'xxxx'
smtp_server = 'xxx'
smtp_port = 587
smtp_password = 'xxx'
def send_notification(subject, body):
"""Send an email notification."""
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = sender_email
msg['To'] = receiver_email
try:
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls()
server.login(sender_email, smtp_password)
server.sendmail(sender_email, receiver_email, msg.as_string())
print("Email sent successfully!")
except Exception as e:
print(f"{e} in ", inspect.stack()[0].function)
def get_vm_status(compute_client):
"""Retrieve the current status of the VM."""
print("Retrieving VM status......")
try:
# Explicitly request the instance view
vm = compute_client.virtual_machines.get(resource_group_name, vm_name, expand='instanceView')
# Check if instance view is available
if vm.instance_view:
print(f"Can you see this message? {inspect.stack()[0].function}")
return vm.instance_view.statuses[1].code # Assuming the status is at index 1
else:
print("Instance view is not available.")
return None
except ClientAuthenticationError as e:
print(f"There was a client authentication error {e}")
except Exception as e:
print(f"Error retrieving VM status: {e}, in function {inspect.stack()[0].function}")
def generate_incident_reference_number():
incident_timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
incident_number = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
return f"INC{incident_timestamp}{incident_number}"
def log_to_azure_monitor():
pass
def main():
print("Entering loop.....",flush=True)
while True:
compute_client = service_principal_authentication()
previous_vm_status = None
current_vm_status = get_vm_status(compute_client)
if current_vm_status != previous_vm_status:
incident_number = generate_incident_reference_number()
print(f"This has changed {current_vm_status} - {previous_vm_status} - {incident_number}", flush=True)
else:
print(f"This has remained the same {current_vm_status}", flush=True)
previous_vm_status = current_vm_status
time.sleep(10)
if __name__ == "__main__":
main()
如前所述,Azure Runbook 具有输出缓冲,这有时会阻止循环内立即显示打印语句。
flush=True
添加到
print
,循环也可能会连续运行,导致输出缓冲无法及时刷新。尝试添加额外的 flush
调用,或者考虑记录日志而不是使用 print
。
while True
循环并使用有限循环或限时循环进行测试,看看是否可以隔离问题。
到达脚本可能会在
get_vm_status
函数之前或在执行函数本身时阻塞。
首先在调用
print
之前添加一个 get_vm_status
语句来检查它是否被调用。然后,在
get_vm_status
函数中,在每个主要操作之前放置打印以跟踪其执行情况。更新代码:
import time
import random
import smtplib
import inspect
import string
from datetime import datetime
from email.mime.text import MIMEText
from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.compute import ComputeManagementClient
from azure.core.exceptions import ClientAuthenticationError
# Azure setup
subscription_id = 'xxx'
resource_group_name = 'xxx'
vm_name = 'xxx'
# Authentication of Azure's Service Principal
def service_principal_authentication():
"""Checks the Authentication of Azure's Service Principal """
print("Authenticating Service Principal....")
try:
credentials = ServicePrincipalCredentials(
client_id='xxx',
secret='xxx',
tenant='xxx'
)
print("Service Principal Authenticity Verified")
return ComputeManagementClient(credentials, subscription_id)
except Exception as e:
print(f"There was an error with the authenticating the Service Principal: {e}")
except ClientAuthenticationError as e:
print(f"Client Authentication Error {e}")
# Email setup
sender_email = 'xxx'
receiver_email = 'xxxx'
smtp_server = 'xxx'
smtp_port = 587
smtp_password = 'xxx'
def send_notification(subject, body):
"""Send an email notification."""
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = sender_email
msg['To'] = receiver_email
try:
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls()
server.login(sender_email, smtp_password)
server.sendmail(sender_email, receiver_email, msg.as_string())
print("Email sent successfully!")
except Exception as e:
print(f"{e} in ", inspect.stack()[0].function)
def get_vm_status(compute_client):
"""Retrieve the current status of the VM."""
print("Entering get_vm_status function.....", flush=True)
try:
print("Retrieving VM status......", flush=True)
# Explicitly request the instance view
vm = compute_client.virtual_machines.get(resource_group_name, vm_name, expand='instanceView')
# Check if instance view is available
if vm.instance_view:
print(f"Can you see this message? {inspect.stack()[0].function}", flush=True)
return vm.instance_view.statuses[1].code # Assuming the status is at index 1
else:
print("Instance view is not available.", flush=True)
return None
except ClientAuthenticationError as e:
print(f"There was a client authentication error {e}", flush=True)
except Exception as e:
print(f"Error retrieving VM status: {e}, in function {inspect.stack()[0].function}", flush=True)
def generate_incident_reference_number():
incident_timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
incident_number = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
return f"INC{incident_timestamp}{incident_number}"
def log_to_azure_monitor():
pass
def main():
print("Entering loop.....", flush=True)
while True:
print("Before calling get_vm_status....", flush=True) # Debug print before calling the function
compute_client = service_principal_authentication()
previous_vm_status = None
current_vm_status = get_vm_status(compute_client)
if current_vm_status != previous_vm_status:
incident_number = generate_incident_reference_number()
print(f"This has changed {current_vm_status} - {previous_vm_status} - {incident_number}", flush=True)
else:
print(f"This has remained the same {current_vm_status}", flush=True)
previous_vm_status = current_vm_status
time.sleep(10)
if __name__ == "__main__":
main()
如果
"Before calling get_vm_status...."
compute_client
或
service_principal_authentication()
方法的初始化。
如果
"Retrieving VM status......"
如果
"Can you see this message?"