def choose_best_instance(self, policy, workload, env): random.seed(self.seed) available_instances = env.get_available_instances() value_by_coordinate = {} for coordinate in Instance.coordinates(): value_by_coordinate[coordinate] = set() for instance in available_instances: for coordinate in Instance.coordinates(): value_by_coordinate[coordinate].add( getattr(instance, coordinate)) print('search space ', value_by_coordinate) coordinates = list(value_by_coordinate.keys()) random.shuffle(coordinates) best_coordinates = {} for coordinate in coordinates: best_coordinates[coordinate] = None best_instance = None for coordinate in coordinates: print('search for best', coordinate) instances_with_run_results = [] for coordinate_value in value_by_coordinate[coordinate]: print('test coordinate_value:', coordinate_value) best_coordinates[coordinate] = coordinate_value suitable_instances = find_suitable_instances( available_instances, best_coordinates) for suitable_instance in suitable_instances: print('test suitable_instance', suitable_instance) results = env.run_workload_on_instance( workload, suitable_instance, self.runs_per_instance) # allocation failed if results.failure and results.mean_cost == 0.0: continue instances_with_run_results.append(results) break if len(instances_with_run_results) == 0: print('not found any suitable_instance for coordinate: ', coordinate) break best_instance = policy.choose_best_instance( instances_with_run_results) best_coordinates[coordinate] = getattr(best_instance, coordinate) print('best coordinates is', best_coordinates) return best_instance
def test_execute_with_complex_inputs(self): step = Step(app='HelloWorld', action='Json Sample', inputs={ 'json_in': { 'a': '-5.6', 'b': { 'a': '4.3', 'b': 5.3 }, 'c': ['1', '2', '3'], 'd': [{ 'a': '', 'b': 3 }, { 'a': '', 'b': -1.5 }, { 'a': '', 'b': -0.5 }] } }) instance = Instance.create(app_name='HelloWorld', device_name='device1') result = step.execute(instance.instance, {}) self.assertIsInstance(result, tuple) self.assertAlmostEqual(result.result, 11.0) self.assertEqual(result.status, 'Success') self.assertTupleEqual(step.output, result)
def test_accumulated_risk_with_error(self): workflow = Workflow(name='workflow') step1 = Step(name="step_one", app='HelloWorld', action='Buggy', risk=1) step2 = Step(name="step_two", app='HelloWorld', action='Buggy', risk=2) step3 = Step(name="step_three", app='HelloWorld', action='Buggy', risk=3.5) workflow.steps = { 'step_one': step1, 'step_two': step2, 'step_three': step3 } workflow.total_risk = 6.5 instance = Instance.create(app_name='HelloWorld', device_name='test_device_name') workflow._Workflow__execute_step(workflow.steps["step_one"], instance) self.assertAlmostEqual(workflow.accumulated_risk, 1.0 / 6.5) workflow._Workflow__execute_step(workflow.steps["step_two"], instance) self.assertAlmostEqual(workflow.accumulated_risk, (1.0 / 6.5) + (2.0 / 6.5)) workflow._Workflow__execute_step(workflow.steps["step_three"], instance) self.assertAlmostEqual(workflow.accumulated_risk, 1.0)
def test_accumulated_risk_with_error(self): workflow = controller.wf.Workflow(name='workflow') workflow.create_step(name="stepOne", app='HelloWorld', action='invalid_name', risk=1) workflow.steps["stepOne"].inputs = { 'call': Argument(key='call', value='HelloWorld', format='str') } workflow.create_step(name="stepTwo", app='HelloWorld', action='repeatBackToMe', risk=2) workflow.steps["stepTwo"].inputs = { 'number': Argument(key='number', value='6', format='str') } workflow.create_step(name="stepThree", app='HelloWorld', action='returnPlusOne', risk=3) workflow.steps["stepThree"].inputs = {} instance = Instance.create(app_name='HelloWorld', device_name='test_device_name') workflow._Workflow__execute_step(workflow.steps["stepOne"], instance=instance()) self.assertEqual(workflow.accumulated_risk, 1.0 / 6.0) workflow._Workflow__execute_step(workflow.steps["stepTwo"], instance=instance()) self.assertEqual(workflow.accumulated_risk, (1.0 / 6.0) + (2.0 / 6.0)) workflow._Workflow__execute_step(workflow.steps["stepThree"], instance=instance()) self.assertEqual(workflow.accumulated_risk, 1.0)
def __execute(self, start='start', input=""): instances = {} total_steps = [] steps = self.__steps(start=start) first = True for step in steps: while self.is_paused: _ = yield if step: if step.name in self.breakpoint_steps: _ = yield callbacks.NextStepFound.send(self) if step.device not in instances: instances[step.device] = Instance.create(step.app, step.device) callbacks.AppInstanceCreated.send(self) step.render_step(steps=total_steps) if first: if input: step.input = input first = False error_flag = self.__execute_step(step, instances[step.device]) total_steps.append(step) steps.send(error_flag) self.__shutdown(instances) yield
def test_execute_action_which_raises_exception(self): from tests.apps.HelloWorld.exceptions import CustomException step = Step(app='HelloWorld', action='Buggy') instance = Instance.create(app_name='HelloWorld', device_name='device1') with self.assertRaises(CustomException): step.execute(instance.instance, {})
def parse_instances(pricing, list_sizes_json, whitelist): available_instances = [] for size in list_sizes_json: name = size['name'] if str.lower(name) not in whitelist: continue cost_per_second = pricing.get_cost_per_second(name) if cost_per_second is None: print('skip {}, price not found'.format(name)) continue n_cpu = int(size['numberOfCores']) n_ram_gb = int(size['memoryInMb']) // 1024 if n_cpu == 0.0 or n_ram_gb == 0.0: continue available_instances.append( Instance(name=name, n_cpu=n_cpu, n_ram_gb=n_ram_gb, cost_per_second=cost_per_second)) print(str(available_instances[-1])) return available_instances
def run(args): local_runner = LocalRunner(json.loads(args.config)) workload = Workload.from_json_str(args.workload) instance = Instance.from_json_str(args.instance) print(local_runner.run(workload, instance).to_json_str())
def __execute(self, start, start_input): instances = {} total_steps = [] steps = self.__steps(start=start) first = True for step in steps: logger.debug('Executing step {0} of workflow {1}'.format( step, self.ancestry)) while self.is_paused: _ = yield if step is not None: if step.name in self.breakpoint_steps: _ = yield callbacks.NextStepFound.send(self) if step.device not in instances: instances[step.device] = Instance.create( step.app, step.device) callbacks.AppInstanceCreated.send(self) logger.debug( 'Created new app instance: App {0}, device {1}'.format( step.app, step.device)) step.render_step(steps=total_steps) if first: first = False if start_input: self.__swap_step_input(step, start_input) error_flag = self.__execute_step(step, instances[step.device]) total_steps.append(step) steps.send(error_flag) self.accumulator[step.name] = step.output self.__shutdown(instances) yield
def test_execute_no_args(self): step = Step(app='HelloWorld', action='helloWorld') instance = Instance.create(app_name='HelloWorld', device_name='device1') self.assertDictEqual(step.execute(instance.instance, {}), {'message': 'HELLO WORLD'}) self.assertDictEqual(step.output, {'message': 'HELLO WORLD'})
def load_instaces(config): simulation_cost = config['costs'] simulation_limits = config['limits'] instances = [] for n_cpu in range(1, int(simulation_limits['max_cpu']) + 1): for n_ram_gb in range(1, int(simulation_limits['max_ram_gb']) + 1): cost_per_second = n_cpu * simulation_cost['cpu_core'] + n_ram_gb * simulation_cost['ram_gb'] instances.append(Instance('custom', n_cpu, n_ram_gb, cost_per_second)) return instances
def read_test(file): instances = [] with open(file, 'r') as handler: for inst in handler: ft = [int(i) for i in inst.split()] instances.append(Instance(len(instances), set(ft[:-1]), ft[-1])) return instances
def test_load_app_function(self): app = 'HelloWorld' with server.running_context.flask_app.app_context(): instance = Instance.create(app, 'default_device_name') existing_actions = {'helloWorld': instance().helloWorld, 'repeatBackToMe': instance().repeatBackToMe, 'returnPlusOne': instance().returnPlusOne} for action, function in existing_actions.items(): self.assertEqual(load_app_function(instance(), action), function)
def from_json_str(json_str): data = json.loads(json_str) return InstanceWithRunResults( Instance.from_json_str(data['instance']), run_results=[ RunResult(failure=bool(data['failure']), elapsed_time=float(data['mean_elapsed']), cost=float(data['mean_cost']), container_metrics={}) ])
def test_as_json_after_executed(self): step = Step(app='HelloWorld', action='helloWorld') instance = Instance.create(app_name='HelloWorld', device_name='device1') step.execute(instance.instance, {}) step_json = step.as_json() self.assertDictEqual( step_json['output'], ActionResult({ 'message': 'HELLO WORLD' }, 'Success').as_json())
def test_execute_with_args(self): step = Step(app='HelloWorld', action='Add Three', inputs={ 'num1': '-5.6', 'num2': '4.3', 'num3': '10.2' }) instance = Instance.create(app_name='HelloWorld', device_name='device1') self.assertAlmostEqual(step.execute(instance.instance, {}), 8.9) self.assertAlmostEqual(step.output, 8.9)
def find_suitable_instances(available_instances, best_coordinates): for instance in available_instances: ok = True for coordinate in Instance.coordinates(): best_value = best_coordinates[coordinate] if best_value == None: continue if best_value != getattr(instance, coordinate): ok = False break if ok: yield instance
def test_execute_with_accumulator_missing_step(self): step = Step(app='HelloWorld', action='Add Three', inputs={ 'num1': '@1', 'num2': '@step2', 'num3': '10.2' }) accumulator = {'1': '-5.6', 'missing': '4.3', '3': '45'} instance = Instance.create(app_name='HelloWorld', device_name='device1') with self.assertRaises(InvalidInput): step.execute(instance.instance, accumulator)
def test_execute_with_accumulator_with_extra_steps(self): step = Step(app='HelloWorld', action='Add Three', inputs={ 'num1': '@1', 'num2': '@step2', 'num3': '10.2' }) accumulator = {'1': '-5.6', 'step2': '4.3', '3': '45'} instance = Instance.create(app_name='HelloWorld', device_name='device1') self.assertAlmostEqual(step.execute(instance.instance, accumulator), 8.9) self.assertAlmostEqual(step.output, 8.9)
def test_execute_with_args(self): step = Step(app='HelloWorld', action='Add Three', inputs={ 'num1': '-5.6', 'num2': '4.3', 'num3': '10.2' }) instance = Instance.create(app_name='HelloWorld', device_name='device1') result = step.execute(instance.instance, {}) self.assertIsInstance(result, tuple) self.assertAlmostEqual(result.result, 8.9) self.assertEqual(result.status, 'Success') self.assertTupleEqual(step.output, result)
def test_execute_invalid_inputs(self): app = 'HelloWorld' actions = [('invalid_name', { 'call': Argument(key='call', value='HelloWorld', format='str') }), ('repeatBackToMe', { 'number': Argument(key='number', value='6', format='str') }), ('returnPlusOne', {})] for action, inputs in actions: step = Step(app=app, action=action, inputs=inputs) with server.running_context.flask_app.app_context(): instance = Instance.create(app_name=app, device_name='test_device_name') with self.assertRaises(InvalidStepInputError): step.execute(instance=instance())
def test_execute_event(self): step = Step(app='HelloWorld', action='Sample Event', inputs={'arg1': 1}) instance = Instance.create(app_name='HelloWorld', device_name='device1') import time from tests.apps.HelloWorld.events import event1 def sender(): gevent.sleep(0.1) event1.trigger(3) start = time.time() gevent.spawn(sender) result = step.execute(instance.instance, {}) end = time.time() self.assertTupleEqual(result, (4, 'Success')) self.assertTrue((end - start) > 0.1)
def load_instaces(config): aws_data = pd.read_csv(config['aws_data_path']) limits = config['limits'] instances = [] for row in aws_data.iterrows(): name = row[1]['name'] n_cpu = row[1]['cpu'] if n_cpu > limits['max_cpu']: continue n_ram_gb = parse_memory(row[1]['memory']) if n_ram_gb > limits['max_ram_gb']: continue cost_per_second = parse_cost(row[1]['cost']) / 60 instances.append(Instance(name, n_cpu, n_ram_gb, cost_per_second)) return instances
def test_execute(self): app = 'HelloWorld' with server.running_context.flask_app.app_context(): instance = Instance.create(app_name=app, device_name='test_device_name') actions = [('helloWorld', {}, { "message": "HELLO WORLD" }), ('repeatBackToMe', { 'call': Argument(key='call', value='HelloWorld', format='str') }, "REPEATING: HelloWorld"), ('returnPlusOne', { 'number': Argument(key='number', value='6', format='str') }, '7')] for action, inputs, output in actions: step = Step(app=app, action=action, inputs=inputs) self.assertEqual(step.execute(instance=instance()), output) self.assertEqual(step.output, output)
def test_load_app_function_invalid_function(self): with server.running_context.flask_app.app_context(): instance = Instance.create('HelloWorld', 'default_device_name') self.assertIsNone(load_app_function(instance(), 'JunkFunctionName'))