def load(self, fleet_service, fleet_service_instance): if not isinstance(fleet_service_instance, FleetService.FleetServiceInstance): raise IllegalArgumentError( "Error: Argument <fleet_service> not instance of type <dynamite.GENERAL.FleetService.FleetServiceInstance>" ) if fleet_service_instance.state == FLEET_STATE_STRUCT.INACTIVE: response = self._change_state(fleet_service_instance, FLEET_STATE_STRUCT.LOADED) # Also load attached services after parent service was loaded if fleet_service_instance.has_attached_services(): for attached_service_instance in fleet_service_instance.attached_services: response = self._change_state(attached_service_instance, FLEET_STATE_STRUCT.LOADED) return response elif fleet_service_instance.state is None: self.submit(fleet_service, fleet_service_instance) # Also load attached services after parent service was loaded if fleet_service_instance.has_attached_services(): for attached_service_instance in fleet_service_instance.attached_services: response = self._change_state(attached_service_instance, FLEET_STATE_STRUCT.LOADED) response = self._change_state(fleet_service_instance, FLEET_STATE_STRUCT.LOADED) return response else: return None
def _change_state(self, fleet_service_instance, new_state): if new_state not in FLEET_STATE_STRUCT.ALLOWED_STATES: raise IllegalArgumentError( "Error: <new_state> values not allowed. Only allowed values are: " + FLEET_STATE_STRUCT.ALLOWED_STATES) fleet_service_instance.state = new_state #fleet_service.unit_file_details_json_dict["desiredState"] = new_state service_name = fleet_service_instance.name request_url = self.fleet_units_url + service_name request_header = self.http_json_content_type_header request_data = json.dumps({"desiredState": new_state}) # curl http://127.0.0.1:49153/fleet/v1/units/example.service -H "Content-Type: application/json" -X PUT -d '{"desiredState": "loaded"}' response = requests.put(request_url, headers=request_header, data=request_data) try: response.raise_for_status() except requests.HTTPError as httpError: raise FleetCommunicationError( "Unable to communicate with fleet while changing the state of unit {} to {}!" .format(service_name, new_state)) from httpError return response.status_code
def add_new_fleet_service_instance(self, fleet_service_name): if not isinstance(fleet_service_name, str): raise IllegalArgumentError("Error: Argument <fleet_service_name> not of type <str>") if fleet_service_name in self.FleetServiceDict: fleet_service = self.FleetServiceDict[fleet_service_name] new_fleet_service_instance = self.FleetServiceHandler.create_new_fleet_service_instance(fleet_service) if new_fleet_service_instance is not None: try: self.FleetServiceHandler.start(fleet_service, new_fleet_service_instance) except FleetSubmissionError as submissionError: self.FleetServiceHandler.remove_fleet_service_instance(fleet_service, new_fleet_service_instance.name, False) raise submissionError # save the updated fleet service into etcd (this is mainly done here to save the updated used_port_numbers # into etcd so that when dynamite restarts it handles those correctly self.save_fleet_service_state_to_etcd(fleet_service) fleet_service_instance_dict = new_fleet_service_instance.to_dict() fleet_service_instance_json = json.dumps(fleet_service_instance_dict) fleet_service_instance_name = fleet_service_instance_dict['name'] etcd_instance_key = ETCDCTL.etcd_key_running_services + "/" + fleet_service.name + "/" + fleet_service_instance_name etcdctl = ETCDCTL.get_etcdctl() etcdctl.write(etcd_instance_key, fleet_service_instance_json) return new_fleet_service_instance return None
def from_scaling_request(scaling_request, success): if not isinstance(success, bool): raise IllegalArgumentError( "Error: argument <success> needs to be of type <bool>") if not isinstance(scaling_request, DynamiteScalingRequest) or scaling_request is None: raise IllegalArgumentError( "Error: argument <scaling_request_string> needs to be of type <str>" ) scaling_response = DynamiteScalingResponse() scaling_response.success = success scaling_response.command = scaling_request.command scaling_response.service_name = scaling_request.service_name scaling_response.service_instance_name = scaling_request.service_instance_name scaling_response.failure_counter = scaling_request.failure_counter return scaling_response
def create_fleet_service_dict_from_dynamite_config_object(self, dynamite_config): if not isinstance(dynamite_config, DynamiteConfig): raise IllegalArgumentError("Error: Argument <dynamite_config> not instance of type 'DynamiteConfig'") self.DynamiteConfig = dynamite_config fleet_service_dict = self.dynamite_config_2_fleet_service_dict(self.DynamiteConfig) if fleet_service_dict is not None: return fleet_service_dict
def from_json_string(cls, scaling_request_string, message_processed_callback=None): if not isinstance(scaling_request_string, str): raise IllegalArgumentError("Error: argument <scaling_request_string> needs to be of type <str>") scaling_request_json = json.loads(scaling_request_string) scaling_request = DynamiteScalingRequest() scaling_request.message_processed_callback = message_processed_callback scaling_request.command = scaling_request_json["command"] scaling_request.service_name = scaling_request_json["service_name"] scaling_request.service_instance_name = scaling_request_json["service_instance_name"] scaling_request.failure_counter = scaling_request_json["failure_counter"] return scaling_request
def generate_scaling_requests(self, scaling_command, service_name=None, service_instance_name=None, number_of_requests=1): if scaling_command not in DynamiteScalingCommand.ALLOWED_COMMANDS: raise IllegalArgumentError( "Error: argument <scaling_command> needs to either be 'scale_up' or 'scale_down'" ) if not isinstance(number_of_requests, int) and number_of_requests < 1: raise IllegalArgumentError( "Error: argument <number_of_requests> needs to be of type <int> and can not" "be less than 1") if service_name is not None: scaling_request = { "command": scaling_command, "service_name": service_name, "service_instance_name": service_instance_name, "failure_counter": 0 } else: raise IllegalArgumentError( "Error: argument <service_name> needs to always be set") scaling_request_string = json.dumps(scaling_request) for requests in range(number_of_requests): # scaling_request_string = self._create_scaling_request_string(scaling_command) self.rabbitmq_channel.basic_publish( exchange='', routing_key=self.dynamite_scaling_request, body=scaling_request_string) print("sent scaling request " + scaling_request_string + " to queue: " + self.dynamite_scaling_request)
def unload(self, fleet_service_instance): if not isinstance(fleet_service_instance, FleetService.FleetServiceInstance): raise IllegalArgumentError( "Error: Argument <fleet_service> not instance of type <dynamite.GENERAL.FleetService.FleetServiceInstance>" ) if fleet_service_instance.state == FLEET_STATE_STRUCT.LOADED or fleet_service_instance.state == FLEET_STATE_STRUCT.LAUNCHED: self._change_state(fleet_service_instance, FLEET_STATE_STRUCT.INACTIVE) # Also unload attached services after parent service was unloaded if fleet_service_instance.has_attached_services(): for attached_service_instances in fleet_service_instance.attached_services: self._change_state(attached_service_instances, FLEET_STATE_STRUCT.INACTIVE)
def _initial_start_all_services_to_fleet(self, fleet_service_handler, fleet_service_dict): if not isinstance(fleet_service_handler, FleetServiceHandler): raise IllegalArgumentError("Error: Argument <FleetServiceHandler> not instance of type <dynamite.GENERAL.FleetServiceHandler") # If service is not a template just create one instance for service_name, fleet_service in fleet_service_dict.items(): if fleet_service.service_config_details.min_instance: min_instances = fleet_service.service_config_details.min_instance else: min_instances = 1 for times in range(min_instances): fleet_service_instance = fleet_service_handler.create_new_fleet_service_instance(fleet_service) fleet_service_handler.submit(fleet_service, fleet_service_instance) fleet_service_handler.start(fleet_service, fleet_service_instance)
def stop(self, fleet_service_instance): if not isinstance(fleet_service_instance, FleetService.FleetServiceInstance): raise IllegalArgumentError( "Error: Argument <fleet_service> not instance of type <dynamite.GENERAL.FleetService.FleetServiceInstance>" ) if fleet_service_instance.state == FLEET_STATE_STRUCT.LAUNCHED: response = self._change_state(fleet_service_instance, FLEET_STATE_STRUCT.LOADED) # Also stop service announcer after parent service was stopped if fleet_service_instance.has_attached_services(): for attached_service_instance in fleet_service_instance.attached_services: response = self._change_state(attached_service_instance, FLEET_STATE_STRUCT.LOADED) return response else: return None
def submit(self, fleet_service, fleet_service_instance): if not isinstance(fleet_service_instance, FleetService.FleetServiceInstance): raise IllegalArgumentError( "Error: Argument <fleet_service> not instance of type <dynamite.GENERAL.FleetService.FleetServiceInstance>" ) if fleet_service.has_attached_services(): for attached_service in fleet_service.attached_services: for name, attached_service_instance in attached_service.fleet_service_instances.items( ): self.submit(attached_service, attached_service_instance) if fleet_service_instance.state is None: service_name = fleet_service_instance.name # fleet_service_instance.unit_file_details_json_dict["desiredState"] = FLEET_STATE_STRUCT.INACTIVE fleet_service.unit_file_details_json_dict[ "desiredState"] = FLEET_STATE_STRUCT.INACTIVE fleet_service_instance.state = FLEET_STATE_STRUCT.INACTIVE #service_json = json.dumps(fleet_service_instance.unit_file_details_json_dict) service_json = json.dumps( fleet_service.unit_file_details_json_dict) request_url = self.fleet_units_url + service_name request_header = self.http_json_content_type_header request_data = service_json # curl http://127.0.0.1:49153/fleet/v1/units/example.service -H "Content-Type: application/json" -X PUT -d @example.service.json response = requests.put(request_url, headers=request_header, data=request_data) self._check_if_unit_exists_and_retry_if_not( fleet_service_instance.name) return response.status_code else: return None
def start(self, fleet_service, fleet_service_instance): if not isinstance(fleet_service_instance, FleetService.FleetServiceInstance): raise IllegalArgumentError( "Error: Argument <fleet_service> not instance of type <dynamite.GENERAL.FleetService.FleetServiceInstance>" ) if fleet_service_instance.state == FLEET_STATE_STRUCT.INACTIVE or fleet_service_instance.state == FLEET_STATE_STRUCT.LOADED: response = self._change_state(fleet_service_instance, FLEET_STATE_STRUCT.LAUNCHED) # Also start service announcer after parent service was started if fleet_service_instance.has_attached_services(): for attached_service in fleet_service_instance.attached_services: response = self._change_state(attached_service, FLEET_STATE_STRUCT.LAUNCHED) return response elif fleet_service_instance.state is None: self.submit(fleet_service, fleet_service_instance) response = self._change_state(fleet_service_instance, FLEET_STATE_STRUCT.LAUNCHED) # Also start attached services after parent service was started if fleet_service_instance.has_attached_services(): for attached_service_instance in fleet_service_instance.attached_services: response = self._change_state(attached_service_instance, FLEET_STATE_STRUCT.LAUNCHED) services_started = self._check_if_service_and_attached_services_started( fleet_service_instance) if not services_started: raise FleetStartError( "Could not start Service {} and or attached services!". format(fleet_service_instance.name)) return response else: return None
def dynamite_config_2_fleet_service_dict(self, dynamite_config): fleet_service_dict = {} if not isinstance(dynamite_config, DynamiteConfig): raise IllegalArgumentError("Error: Argument not instance of type 'DynamiteConfig'") # Collect necessary information of services defined in 'config.yaml' file and save them in 'service_dict' # dictionary service_dict = {} for service_attributes in dynamite_config.Service.__dict__.values(): service_dict[service_attributes.name] = {"service_name": service_attributes.name, "name_of_unit_file": service_attributes.name_of_unit_file, "service_details": service_attributes} # Create a dictionary (file --> path) of the files contained in the folder(s) in # dynamite_config.ServiceFiles.PathList dict_of_files = {} for service_file_folder in dynamite_config.ServiceFiles.PathList: list_of_files = os.listdir(service_file_folder) for file in list_of_files: abs_path_of_file = os.path.join(service_file_folder, file) if os.path.isfile(abs_path_of_file): if file in dict_of_files: raise DuplicateServiceFileError("Error: " + file + " was found 2 times") else: dict_of_files[file] = abs_path_of_file # Go through all the services defined in the dynamite configuration (Dynamite.Service.<x>) # # Raises an error if any 'Dynamite.Service.<ServiceName>.name_of_unit_file' does not exists in any of the # paths defined in 'Dynamite.ServiceFiles.PathList # # If the file exits a new FleetService gets created # If the file/service uses an attached service a FleetService for the attached service gets created and # attached to the 'original/parent' FleetService # that attaches the services as defined in the DynamiteConfig. The attached service should be saved in a # list or dictionary for service_name, service_info_dict in service_dict.items(): name_of_unit_file = service_info_dict["name_of_unit_file"] if name_of_unit_file in dict_of_files and service_info_dict["service_details"].type != "attached_service": service_details = service_info_dict["service_details"] path_to_unit_file = dict_of_files[name_of_unit_file] json_dict = self.unit2dict(path_to_unit_file) service_is_template = True if "@" in service_details.name_of_unit_file else False attached_services = [] if service_details.attached_services is not None: for attached_service in service_details.attached_services: name_of_attached_service = attached_service attached_service_details = getattr(dynamite_config.Service, name_of_attached_service) name_of_attached_service_unit_file = attached_service_details.name_of_unit_file if name_of_attached_service_unit_file in dict_of_files: attached_service_is_template = True if "@" in service_details.name_of_unit_file else False path_to_attached_service_unit_file = dict_of_files[name_of_attached_service_unit_file] attached_service_json_dict = self.unit2dict(path_to_attached_service_unit_file) attached_service = FleetService(name_of_attached_service, path_to_attached_service_unit_file, attached_service_json_dict, attached_service_details, is_template=attached_service_is_template, attached_services=None) attached_services.append(attached_service) else: self._logger.error(name_of_attached_service_unit_file + "> File was not found.") #raise ServiceAnnouncerFileNotFoundError("Error: <" + name_of_attached_service_unit_file + "> File was not found.") fleet_service = FleetService(service_name, path_to_unit_file, json_dict, service_details, service_is_template, attached_services) fleet_service_dict[service_info_dict["service_name"]] = fleet_service # TODO: find out if attached service elif service_info_dict["service_details"].type == "attached_service": pass else: raise ServiceFileNotFoundError(name_of_unit_file + " Service-File was not found") return fleet_service_dict