class ApiRandomCaller: def __init__(self, api, methods, seed=None, chaos_monkey=True): self.api = api self.methods = methods self.methods_list = methods.values() self.ig = InputGenerator(seed, chaos_monkey) def call(self, method, inputs=None): try: event = method.call(self.api, params=inputs) except requests.exceptions.ConnectionError: print "[E] Couldn't call %s/%s" % ( method.base_url, method.url) method.enabled = False return None # Remove resources that results in a 404 if event.code == 404 and 'url_input' in inputs: for input_name, input_value in inputs['url_input'].items(): self.ig.resource_remove(input_name, input_value) # Remove resources that were deleted if method.http_method == 'DELETE' and event.code >= 200 and event.code < 300: for input_name, input_value in inputs['url_input'].items(): self.ig.resource_remove(input_name, input_value) # Adds output to resources self.ig.resources_add(event.outputs) return event def step(self, ask_before_call=False): random.shuffle(self.methods_list) # Pick a callable method for method in self.methods_list: if not method.enabled: continue # Tries to avoid delete and list if (method.http_method != 'DELETE' and not method.name.endswith('_list')) or self.ig.once_every(100): break if not method.enabled: print "Couldn't find a working method, abort" exit(1) # Generate inputs inputs = self.ig.generate_inputs(method.inputs) if ask_before_call: raw_input("\nPress enter to call %s (%s/%s) -d '%s' " % (method.name, method.base_url, method.url, inputs)) return self.call(method, inputs) def sync_resources(self): # Refresh internal resources list tenant_id = self.ig.resources.setdefault('tenant_id', None) self.ig.resources_clear() if tenant_id: self.ig.resources["tenant_id"] = tenant_id for name, method in self.methods.items(): if not name.endswith("_list"): continue try: event = method.call(self.api) except requests.exceptions.ConnectionError: print "[E] Couldn't call %s/%s" % ( method.base_url, method.url) continue # Adds output to resources self.ig.resources_add(event.outputs)