I ran the code at the bottom of this post in my environment and got the following error after a few successes:
An error occurred (SnapshotCreationPerVolumeRateExceeded) when calling the CreateSnapshot operation: The maximum per volume CreateSnapshot request rate has been exceeded. Use an increasing or variable sleep interval between requests.
I'm used to doing something like this to paginate my results using a MaxResults variable and the NextToken returned by the response:
maxResults = 100
result = ec2.describe_instances(MaxResults=maxResults)
nextToken = result['NextToken']
instance_ids = []
for reservation in result['Reservations']:
for instances in reservation['Instances']:
for i in instances:
instance_ids.append(i['InstanceId'])
size = len(instance_ids)
while size == maxResults:
result = ec2.describe_instances(MaxResults=maxResults, NextToken=nextToken)
nextToken = result['NextToken']
size = len(instance_ids)
# etc...
However, because I'm already filtering by tag in my describe_instances call, I'm not allowed to pass a maxResults parameter as well. Additionally, create_snapshot's call signature only allows me to specify a dry run, the volume ID, and a description of the snapshot, and does not return a nextToken or similar. How can I avoid this error - must I introduce a sleep like the error message suggests?
Lambda function code:
from __future__ import print_function
import boto3
import datetime
import time
ec2 = boto3.client('ec2')
def createScheduleSnapshots(event, context):
errors = []
try:
print("Creating snapshots on " + str(datetime.datetime.today()) + ".")
schedulers = ec2.describe_instances(Filters=[{'Name':'tag:GL-sub-purpose', 'Values':['Schedule']}])
schedule_instances = []
for reservation in schedulers['Reservations']:
for instance in reservation['Instances']:
schedule_instances.append(instance)
print("Performing backup on " + str(len(schedule_instances)) + " schedules.")
successful = []
failed = []
for s in schedule_instances:
try:
instanceId=s['InstanceId']
blockDeviceMappings = s['BlockDeviceMappings']
snapshotDescription = instanceId + "-" + str(datetime.date.today().strftime('%Y-%m-%d')) + "-46130e7ac954-automated"
for bd_maps in blockDeviceMappings:
if (bd_maps['DeviceName'] == '/dev/sdf'): #Don't back up OS
volumeId = bd_maps['Ebs']['VolumeId']
print("\tSnapshotting " + instanceId)
ec2.create_snapshot(
VolumeId=volumeId,
Description=snapshotDescription
)
successful.append(instanceId)
except Exception as e:
print(e)
errors.append(e)
failed.append(instanceId + " :\t" + str(e))
print("Performed backup on " + str(len(successful)) + " schedulers. Failed backup on " + str(len(failed)) + " schedulers. ")
except Exception as e:
print(e)
errors.append(e)
if len(errors) == 0:
return "Success"
else:
raise Exception("Errors during invocation of Lambda. " + str(errors))
Related
new in asyncio world.
going straight to the point...
I want to do/make a request(aiohttp) to a site.
if the wait for an answer pass than N seconds I want to stop the process of waiting.
Do the process again by setting a limit of attempts if needed.
async def search_skiping_add(name_search):
start_time = time()
async with aiohttp.ClientSession() as session:
url = f'https://somesitehere.com'
r = await session.get(url)
final_time = time()
result_time =round(final_time-start_time)
print(result_time)
Maybe, I know, have some way to do it synchronously, but it's an excuse to start using asyncio somehow too.
This should give you an idea of how to use async with aiohttp:
from aiohttp import ClientSession
from asyncio import gather, create_task, sleep, run
from traceback import format_exc
def returnPartionedList(inputlist: list, x: int = 100) -> list: # returns inputlist split into x parts, default is 100
return([inputlist[i:i + x] for i in range(0, len(inputlist), x)])
# You could change validate to an integer and thereby increasing the retry count as needed.
async def GetRessource(url: str, session: ClientSession, validate: bool = False) -> dict:
try:
async with session.get(url) as response:
if response.status == 200:
r: dict = await response.json() # Set equal to .text() to get results as a string
return(r)
else:
r: str = await response.text()
if not validate:
await sleep(3) # Sleep for x amount of seconds before retry
return(await GetRessource(url, session, True))
print(f"Error, got response code: {response.status} message: {r}")
except Exception:
print(f"General Exception:\n{format_exc()}")
return({})
async def GetUrls(urls: list) -> list:
resultsList: list = []
UrlPartitions: list = returnPartionedList(urls, 20) # Rate limit to 20 requests per loop
async with ClientSession(timeout=15) as session: # Timeout is equal to the time to wait in seconds before terminating, default is 300 seconds or 5 minutes.
for partition in UrlPartitions:
partitionTasks: list = [create_task(GetRessource(url, session)) for url in partition]
resultsList.append(await gather(*partitionTasks, return_exceptions=False))
return(resultsList) # Or you can do more processing here before returning
async def main():
urls: list = ["...", "...", "..."] # list of urls to get from
results: list = await GetUrls(urls)
print(results)
if __name__ == "__main__":
run(main())
I wanted to report some debug information for a parser I am writing in lua. I am using the debug hook facility for tracking but it seems like there is some form of race condition happening.
Here is my test code:
enters = 0
enters2 = 0
calls = 0
tailcalls = 0
returns = 0
lines = 0
other = 0
exits = 0
local function analyze(arg)
enters = enters + 1
enters2 = enters2 + 1
if arg == "call" then
calls = calls + 1
elseif arg == "tail call" then
tailcalls = tailcalls + 1
elseif arg == "return" then
returns = returns + 1
elseif arg == "line" then
lines = lines + 1
else
other = other + 1
end
exits = exits + 1
end
debug.sethook(analyze, "crl")
-- main code
print("enters = ", enters)
print("enters2 = ", enters2)
print("calls = ", calls)
print("tailcalls = ", tailcalls)
print("returns = ", returns)
print("lines = ", lines)
print("other = ", other)
print("exits = ", exits)
print("sum = ", calls + tailcalls + returns + lines + other)
and here is the result:
enters = 429988
enters2 = 429991
calls = 97433
tailcalls = 7199
returns = 97436
lines = 227931
other = 0
exits = 430009
sum = 430012
Why does none of this add up? I am running lua 5.4.2 on Ubuntu 20.04, no custom c libraries, no further messing with the debug library.
I found the problem...
The calls to the print function when printing the result also trigger the hook, which only affects the results that have not been printed yet.
Hi I am trying to run a schedule script, not via lambda but from a pc or onsite schedule job - maybe every 10 mins or so to check all my ec2 instances are failing any system/instance status checks. If it fails then send email of the ec2 instance that failing - just send the name. Do not reboot
so here is what i have
import boto3
import smtplib
region_name='us-west-1'
#ec2_client = boto3.client('ec2')
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
#response = ec2_client.describe_instance_status(IncludeAllInstances = True)
client = boto3.client("ec2")
clientsns = boto3.client("sns")
#response = clientsns.create_topic
status = client.describe_instance_status(IncludeAllInstances = True)
#for instance in response['InstanceStatuses']:
# instance_id = instance['InstanceId']
# system_status = instance['SystemStatus']
# instance_status = instance['InstanceStatus']
# print (instance_id, system_status, instance_status)
for i in status["InstanceStatuses"]:
print("AvailabilityZone :", i["AvailabilityZone"])
print("InstanceId :", i["InstanceId"])
print("InstanceState :", i["InstanceState"])
print("InstanceStatus", i["InstanceStatus"])
print("SystemStatus", i["SystemStatus"])
in_status = i['InstanceStatus']['Details'][0]['Status']
sys_status = i['SystemStatus']['Details'][0]['Status']
msg1 = 'The following instances failed status checks, i[{InstanceId}]'
msg2 = 'All Instances passed System/instance checks!'
# check statuses
if ((in_status != 'passed') or (sys_status != 'passed')):
print(bcolors.WARNING + 'Reboot required for', i["InstanceId"] + bcolors.ENDC)
clientsns.publish(TopicArn='arn:aws:sns:us-west-1:462518063038:test',Message=msg1)
else:
print('All Instances passed System/instance checks!')
clientsns.publish(TopicArn='arn:aws:sns:us-west-1:462518063038:test',Message=msg2)
The problem I have is its sending one message per instance. I just wwant to sent one email for all instances. any idea?
Thank you
So this is 100% a wip and I'm super confused on how to stop the discord bot from reading the same user message over and over again.
import discord
class MyClient(discord.Client):
async def on_ready(self):
print('Logged in as')
print(self.user.name)
print(self.user.id)
print('------')
async def on_message(self, message):
global choice
global r
# we do not want the bot to reply to itself
if message.author.id == self.user.id:
return
if message.content.startswith('!hello'):
await message.reply('Hello!', mention_author=True)
r=0
basic = True
#upgrade1 = False
choice = '!idle'
while(choice != '!end'):
if message.content.startswith('!idle'):
choice= await message.reply('!click / !bank / !upgrade / !minigame / !end')
if message.author.id == self.user.id:
return
if message.content.startswith('!click' or '!c'):
r = r + 1
await message.reply("You have " + str(r) + " Renown")
elif message.content.startswith ('!bank'):
await message.reply ("You have " + str(r) + " Renown")
#elif message.content.startswith ('!upgrade' and r >= 10):
#await message.reply('Upgrading..')
#r = r - 10
#basic = False
#elif message.content.startswith ('!upgrade' and r < 10):
#await message.reply ('Not Enough Renown')
elif message.content.startswith('!minigame' or '!mg'):
#random number choosing game
await message.reply ("Game")
elif message.content.startswith ('!end'):
basic = False
#while time.time() < future:
#r =r + .00001
client = MyClient()
client.run
Your issue comes from the while(choice != '!end') loop. Once the bot enters that loop, the messages he is sending within that loop of course will be repeated because you are not changing the value of choice unless the message is !idle.
Notice in your code how if the command is for example !click, you are sending the following message:
await message.reply("You have " + str(r) + " Renown")
But you are not changing the value of choice, so in the next iteration of the while loop it will repeat the same, once and again.
I'm not sure what you are trying to achieve, but having a while loop in the on_message event does not seem a good idea for me, as this is a blocking feature. In my opinion you should replace it with an if.
So, I'm making a modmail bot for my discord server. But when I run, the bot can connect but when I send a test messange in the bot DM, I receive this error: AttributeError: 'NoneType' object has no attribute 'send'.
I'm using python 3.9.1 on Arch Linux. Here is my code:
import discord
from discord.ext.commands import Bot
from discord.ext import commands
import asyncio
client = commands.Bot(command_prefix="!")
#client.event
async def on_ready():
await client.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name='for moderation mail'))
print("Thunderbird is ready")
#client.event
async def on_message(message):
empty_array = []
modmail_channel = discord.utils.get(client.get_all_channels(), name="modmail-box")
if message.author == client.user:
return
if str(message.channel.type) == "private":
if message.attachments != empty_array:
files = message.attachments
await modmail_channel.send("<#" + message.author.id + ">: ")
for file in files:
await modmail_channel.send(file.url)
else:
await modmail_channel.send("<#" + str(message.author.id) + ">: " + message.content)
elif str(message.channel) == "modmail" and message.content.startswith("<"):
member_object = message.mentions[0]
if message.attachments != empty_array:
files = message.attachments
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: ")
for file in files:
await member_object.send(file.url)
else:
index = message.content.index(" ")
string = message.content
mod_message = string[index:]
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: " + mod_message)
client.run('No leaking here')
I am assuming that the error is on this line:
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: ")
and member_object is coming from this block:
elif str(message.channel) == "modmail" and message.content.startswith("<"):
member_object = message.mentions[0]
if message.attachments != empty_array:
files = message.attachments
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: ")
for file in files:
await member_object.send(file.url)
You are defining member_object as the first element in the message.mentions array, however your error of NoneType has no attribute suggests that there are no elements in that array and so member_object is actually equal to None not an instance of a class which has a send method.
You need to check your input to that function and ensure that when your code reaches that block it actually has the attributes that you are expecting