def handle(self): input_command = self.request.input.command or '' if not input_command: msg = 'No command sent' raise ZatoException(self.cid, msg) try: parse_result = redis_grammar.parseString(input_command) options = {} command = parse_result.command parameters = parse_result.parameters if parse_result.parameters else [] if command == 'CONFIG': options['parse'] = parameters[0] elif command == 'OBJECT': options['infotype'] = parameters[0] response = self.server.kvdb.conn.execute_command( command, *parameters, **options) or '' if response and command in ('KEYS', 'HKEYS', 'HVALS'): response = unicode(response).encode('utf-8') elif command in ('HLEN', 'LLEN', 'LRANGE', 'SMEMBERS', 'HGETALL'): response = str(response) self.response.payload.result = response or '(None)' except Exception, e: msg = 'Command parsing error, command:[{}], e:[{}]'.format( input_command, format_exc(e)) self.logger.error(msg) raise ZatoException(self.cid, msg)
def invoke_by_impl_name(self, impl_name, payload='', channel=CHANNEL.INVOKE, data_format=DATA_FORMAT.DICT, transport=None, serialize=False, as_bunch=False, timeout=None, raise_timeout=True, **kwargs): """ Invokes a service synchronously by its implementation name (full dotted Python name). """ if self.component_enabled_target_matcher: orig_impl_name = impl_name impl_name, target = self.extract_target(impl_name) # It's possible we are being invoked through self.invoke or self.invoke_by_id target = target or kwargs.get('target', '') if not self._worker_store.target_matcher.is_allowed(target): raise ZatoException(self.cid, 'Invocation target `{}` not allowed ({})'.format(target, orig_impl_name)) if self.component_enabled_invoke_matcher: if not self._worker_store.invoke_matcher.is_allowed(impl_name): raise ZatoException(self.cid, 'Service `{}` (impl_name) cannot be invoked'.format(impl_name)) if self.impl_name == impl_name: msg = 'A service cannot invoke itself, name:[{}]'.format(self.name) self.logger.error(msg) raise ZatoException(self.cid, msg) service, is_active = self.server.service_store.new_instance(impl_name) if not is_active: raise Inactive(service.get_name()) set_response_func = kwargs.pop('set_response_func', service.set_response_data) invoke_args = (set_response_func, service, payload, channel, data_format, transport, self.server, self.broker_client, self._worker_store, kwargs.pop('cid', self.cid), self.request.simple_io_config) kwargs.update({'serialize':serialize, 'as_bunch':as_bunch}) try: if timeout: try: g = spawn(self.update_handle, *invoke_args, **kwargs) return g.get(block=True, timeout=timeout) except Timeout: g.kill() logger.warn('Service `%s` timed out (%s)', service.name, self.cid) if raise_timeout: raise else: out = self.update_handle(*invoke_args, **kwargs) if kwargs.get('skip_response_elem') and hasattr(out, 'keys'): keys = list(iterkeys(out)) response_elem = keys[0] return out[response_elem] else: return out except Exception: logger.warn('Could not invoke `%s`, e:`%s`', service.name, format_exc()) raise
def get(self, name): params = { 'hostname': None, 'database': None, 'port': None, 'login': None, 'password': None } missing = [] for param in params: key_prefix = OE_PARAMS[param] key = ':'.join((key_prefix, name)) value = self.kvdb.conn.get(key) if not value: missing.append(key) else: value = int(value) if param == 'port' else value params[param] = value if missing: msg = 'One or more config key is missing or has no value: {}'.format( missing) self.logger.error(msg) raise ZatoException(self.cid, msg) client = Client(**params) client.connect() return client
def get(self, name): params = { 'smtp_port': 25, 'smtp_debug': False, 'smtp_encryption': None, } missing = [] for param in SMTP_PARAMS: key_prefix = SMTP_PARAMS[param] key = ':'.join((key_prefix, name)) value = self.kvdb.conn.get(key) if not value and not params.get(param, False): missing.append(key) else: if param == 'smtp_port': value = int(value) elif param == 'smtp_debug': if value == 'True': value = True else: value = False params[param] = value if missing: msg = 'One or more config key is missing or has no value: {}'.format( missing) self.logger.error(msg) raise ZatoException(self.cid, msg) client = SMTPClient(**params) client.connect() return client
def handle(self): with closing(self.odb.session()) as session: try: server = session.query(Server).\ filter(Server.id==self.request.input.id).\ one() # Sanity check if server.id == self.server.id: msg = 'A server cannot delete itself, id:[{}], name:[{}]'.format( server.id, server.name) self.logger.error(msg) raise ZatoException(self.cid, msg) # This will cascade and delete every related object session.delete(server) session.commit() except Exception, e: session.rollback() msg = 'Could not delete the server, e:[{e}]'.format( e=format_exc(e)) self.logger.error(msg) raise
def _getvalue(self, name, item, is_sa_namedtuple, is_required, leave_as_is): """ Returns an element's value if any has been provided while taking into account the differences between dictionaries and other formats as well as the type conversions. """ lookup_name = name.name if isinstance(name, ForceType) else name if is_sa_namedtuple or self._is_sqlalchemy(item): elem_value = getattr(item, lookup_name, '') else: elem_value = item.get(lookup_name, '') if isinstance(elem_value, basestring) and not elem_value: msg = self._missing_value_log_msg(name, item, is_sa_namedtuple, is_required) if is_required: self.zato_logger.debug(msg) raise ZatoException(self.zato_cid, msg) else: if self.zato_logger.isEnabledFor(TRACE1): self.zato_logger.log(TRACE1, msg) if leave_as_is: return elem_value else: return self.convert(name, lookup_name, elem_value, True, self.zato_is_xml, self.bool_parameter_prefixes, self.int_parameters, self.int_parameter_suffixes, None, self.zato_data_format, True)
def invoke_by_impl_name(self, impl_name, payload='', channel=CHANNEL.INVOKE, data_format=None, transport=None, serialize=False, as_bunch=False): """ Invokes a service synchronously by its implementation name (full dotted Python name). """ if self.impl_name == impl_name: msg = 'A service cannot invoke itself, name:[{}]'.format(self.name) self.logger.error(msg) raise ZatoException(self.cid, msg) service = self.server.service_store.new_instance(impl_name) return self.update_handle(self.set_response_data, service, payload, channel, data_format, transport, self.server, self.broker_client, self.worker_store, self.cid, self.request.simple_io_config, serialize=serialize, as_bunch=as_bunch)
def handle(self): with closing(self.odb.session()) as session: try: service = session.query(Service).\ filter(Service.id==self.request.input.id).\ one() internal_del = is_boolean(self.server.fs_server_config.misc. internal_services_may_be_deleted) if service.is_internal and not internal_del: msg = "Can't delete service:[{}], it's an internal one and internal_services_may_be_deleted is not True".format( service.name) raise ZatoException(self.cid, msg) # This will also cascade to delete the related DeployedService objects session.delete(service) session.commit() msg = { 'action': SERVICE.DELETE.value, 'id': self.request.input.id, 'impl_name': service.impl_name, 'is_internal': service.is_internal } self.broker_client.publish(msg) except Exception: session.rollback() msg = 'Service could not be deleted, e:`{}`'.format( format_exc()) self.logger.error(msg) raise
def payload_from_request(cid, request, data_format, transport): """ Converts a raw request to a payload suitable for usage with SimpleIO. """ if request is not None: if data_format == DATA_FORMAT.XML: if transport == 'soap': if isinstance(request, objectify.ObjectifiedElement): soap = request else: soap = objectify.fromstring(request) body = soap_body_xpath(soap) if not body: raise ZatoException( cid, 'Client did not send the [{}] element'.format( soap_body_path)) payload = get_body_payload(body) else: if isinstance(request, objectify.ObjectifiedElement): payload = request else: payload = objectify.fromstring(request) elif data_format in (DATA_FORMAT.DICT, DATA_FORMAT.JSON): if not request: return '' if isinstance(request, basestring) and data_format == DATA_FORMAT.JSON: payload = loads(request) else: payload = request else: payload = request else: payload = request return payload
def _validate_tls(self, input, sec_info): if sec_info['sec_type'] == SEC_DEF_TYPE.TLS_KEY_CERT: if not input.get('sec_tls_ca_cert_id'): raise ZatoException( self.cid, 'TLS CA certs is a required field if TLS keys/certs are used' )
def _get_slice_period_type(self, start, stop, orig_start, orig_stop): """ Returns information regarding whether a given period should be sliced by minutes, hours, days, months and/or years. """ start = Date(start) stop = Date(stop) if start > stop: msg = 'start:[{}] must not be greater than stop:[{}]'.format(orig_start, orig_stop) raise ZatoException(self.cid, msg) delta = stop - start by_mins = False by_hours_mins = False by_days_hours_mins = False by_months_days_hours_mins = False by_mins = delta.total_minutes <= 60 by_hours_mins = delta.total_minutes > 60 by_days_hours_mins = delta.total_days > 1 by_months_days_hours_mins = delta.total_months > 1 if any((by_days_hours_mins, by_months_days_hours_mins)): by_hours_mins = False if by_months_days_hours_mins: by_days_hours_mins = False return delta, { 'by_mins': by_mins, 'by_hours_mins': by_hours_mins, 'by_days_hours_mins': by_days_hours_mins, 'by_months_days_hours_mins': by_months_days_hours_mins, }
def init(self, is_sio, cid, sio, data_format, transport, wsgi_environ): """ Initializes the object with an invocation-specific data. """ if is_sio: self.is_xml = data_format == SIMPLE_IO.FORMAT.XML self.data_format = data_format self.transport = transport self._wsgi_environ = wsgi_environ path_prefix = getattr(sio, 'request_elem', 'request') required_list = getattr(sio, 'input_required', []) optional_list = getattr(sio, 'input_optional', []) default_value = getattr(sio, 'default_value', NO_DEFAULT_VALUE) use_text = getattr(sio, 'use_text', True) use_channel_params_only = getattr(sio, 'use_channel_params_only', False) if self.simple_io_config: self.has_simple_io_config = True self.bool_parameter_prefixes = self.simple_io_config.get( 'bool_parameter_prefixes', []) self.int_parameters = self.simple_io_config.get( 'int_parameters', []) self.int_parameter_suffixes = self.simple_io_config.get( 'int_parameter_suffixes', []) else: self.payload = self.raw_request required_params = {} if required_list: # Needs to check for this exact default value to prevent a FutureWarning in 'if not self.payload' if self.payload == '' and not self.channel_params: raise ZatoException(cid, 'Missing input') required_params.update( self.get_params(required_list, use_channel_params_only, path_prefix, default_value, use_text)) if optional_list: optional_params = self.get_params(optional_list, use_channel_params_only, path_prefix, default_value, use_text, False) else: optional_params = {} self.input.update(required_params) self.input.update(optional_params) for param, value in self.channel_params.iteritems(): if param not in self.input: self.input[param] = value # We merge channel params in if requested even if it's not SIO else: if self.merge_channel_params: self.input.update(self.channel_params)
def _invoke(self, name=None, payload='', headers=None, channel='invoke', data_format='json', transport=None, is_async=False, expiration=BROKER.DEFAULT_EXPIRATION, id=None, to_json=True, output_repeated=ZATO_NOT_GIVEN, pid=None, all_pids=False, timeout=None): if not(name or id): raise ZatoException(msg='Either name or id must be provided') if name and output_repeated == ZATO_NOT_GIVEN: output_repeated = name.lower().endswith('list') if to_json: payload = dumps(payload, default=default_json_handler) id_, value = ('name', name) if name else ('id', id) request = { id_: value, 'payload': b64encode(payload.encode('utf8') if PY3 else payload), 'channel': channel, 'data_format': data_format, 'transport': transport, 'is_async': is_async, 'expiration':expiration, 'pid':pid, 'all_pids': all_pids, 'timeout': timeout, } return super(AnyServiceInvoker, self).invoke(dumps(request, default=default_json_handler), ServiceInvokeResponse, is_async, headers, output_repeated)
def connect(self): if self.smtp_encryption == 'ssl': if not 'SMTP_SSL' in smtplib.__all__: raise ZatoException( self.cid, "SMTP-over-SSL mode unavailable, Your Zato Server does not support SMTP-over-SSL. You could use STARTTLS instead. If SSL is needed, an upgrade to Python 2.6 on the server-side should do the trick." ) self.conn = smtplib.SMTP_SSL(self.smtp_host, self.smtp_port) else: self.conn = smtplib.SMTP(self.smtp_host, self.smtp_port) self.conn.set_debuglevel(self.smtp_debug) if self.smtp_encryption == 'starttls': # starttls() will perform ehlo() if needed first # and will discard the previous list of services # after successfully performing STARTTLS command, # (as per RFC 3207) so for example any AUTH # capability that appears only on encrypted channels # will be correctly detected for next step self.conn.starttls() if self.smtp_user: # Attempt authentication - will raise if AUTH service not supported # The user/password must be converted to bytestrings in order to be usable for # certain hashing schemes, like HMAC. # See also bug #597143 and python issue #5285 self.conn.login(self.smtp_user, self.smtp_pass) return self.conn
def handle(self): payload = self.request.input.get('payload') if payload: payload = payload_from_request(self.cid, payload.decode('base64'), self.request.input.data_format, self.request.input.transport) id = self.request.input.get('id') name = self.request.input.get('name') pid = self.request.input.get('pid') channel = self.request.input.get('channel') data_format = self.request.input.get('data_format') transport = self.request.input.get('transport') expiration = self.request.input.get( 'expiration') or BROKER.DEFAULT_EXPIRATION if name and id: raise ZatoException( 'Cannot accept both id:`{}` and name:`{}`'.format(id, name)) if self.request.input.get('async'): if id: impl_name = self.server.service_store.id_to_impl_name[id] name = self.server.service_store.service_data( impl_name)['name'] # If PID is given on input it means we must invoke this particular server process by it ID if pid: response = self.server.invoke_by_pid(name, payload, pid) else: response = self.invoke_async(name, payload, channel, data_format, transport, expiration) else: # Same as above in async branch if pid: response = self.server.invoke(name, payload, pid=pid, data_format=data_format) else: func, id_ = (self.invoke, name) if name else (self.invoke_by_id, id) response = func(id_, payload, channel, data_format, transport, serialize=True) if isinstance(response, basestring): if response: self.response.payload.response = response.encode( 'base64') if response else ''
def _validate_entry(self, validate_item, id=None): for elem in('system', 'key'): name = self.request.input[elem] match = self.NAME_RE.match(name) if match and match.group() == name: continue else: msg = "System and key may contain only letters, digits and an underscore, failed to validate [{}] against the regular expression {}".format( name, self.NAME_PATTERN) raise ZatoException(self.cid, msg) for item in self._get_dict_items(): joined = KVDB.SEPARATOR.join((item['system'], item['key'], item['value'])) if validate_item == joined and id != item['id']: msg = 'The triple of system:[{}], key:[{}], value:[{}] already exists'.format(item['system'], item['key'], item['value']) raise ZatoException(self.cid, msg) return True
def init_flat_sio(self, cid, sio, data_format, transport, wsgi_environ, required_list): """ Initializes flat SIO requests, i.e. not list ones. """ self.is_xml = data_format == SIMPLE_IO.FORMAT.XML self.data_format = data_format self.transport = transport self._wsgi_environ = wsgi_environ optional_list = getattr(sio, 'input_optional', []) optional_list = [optional_list] if isinstance( optional_list, basestring) else optional_list path_prefix = getattr(sio, 'request_elem', 'request') default_value = getattr(sio, 'default_value', NO_DEFAULT_VALUE) use_text = getattr(sio, 'use_text', True) use_channel_params_only = getattr(sio, 'use_channel_params_only', False) self.encrypt_secrets = getattr(sio, 'encrypt_secrets', True) if self.simple_io_config: self.has_simple_io_config = True self.bool_parameter_prefixes = self.simple_io_config.get( 'bool_parameter_prefixes', []) self.int_parameters = self.simple_io_config.get( 'int_parameters', []) self.int_parameter_suffixes = self.simple_io_config.get( 'int_parameter_suffixes', []) else: self.payload = self.raw_request required_params = {} if required_list: # Needs to check for this exact default value to prevent a FutureWarning in 'if not self.payload' if self.payload == '' and not self.channel_params: raise ZatoException(cid, 'Missing input') required_params.update( self.get_params(required_list, use_channel_params_only, path_prefix, default_value, use_text)) if optional_list: optional_params = self.get_params(optional_list, use_channel_params_only, path_prefix, default_value, use_text, False) else: optional_params = {} self.input.update(required_params) self.input.update(optional_params) for param, value in self.channel_params.iteritems(): if param not in self.input: self.input[param] = value
def _get_dict_item(self, id): """ Returns a dictionary entry by its ID. """ for item in self._get_dict_items(): if item['id'] == str(id): return item else: msg = 'Could not find the dictionary by its ID:[{}}]'.format(id) raise ZatoException(self.cid, msg)
def convert_sio(cid, param, param_name, value, has_simple_io_config, is_xml, bool_parameter_prefixes, int_parameters, int_parameter_suffixes, encrypt_func, date_time_format=None, data_format=ZATO_NONE, from_sio_to_external=False, special_values=(ZATO_NONE, ZATO_SEC_USE_RBAC), _is_bool=is_bool, _is_int=is_int, _is_secret=is_secret): try: if _is_bool(param, param_name, bool_parameter_prefixes): value = asbool( value or None) # value can be an empty string and asbool chokes on that if value is not None: if isinstance(param, ForceType): value = param.convert(value, param_name, data_format, from_sio_to_external) else: # Empty string sent in lieu of integers are equivalent to None, # as though they were never sent - this is need for internal metaclasses if value == '' and _is_int(param_name, int_parameters, int_parameter_suffixes): value = None if value and (value not in special_values) and has_simple_io_config: if _is_int(param_name, int_parameters, int_parameter_suffixes): value = int(value) elif _is_secret(param_name): # It will be None in SIO responses if encrypt_func: value = encrypt_func(value) return value except Exception, e: if isinstance(e, Reportable): e.cid = cid raise else: msg = 'Conversion error, param:`{}`, param_name:`{}`, repr:`{}`, type:`{}`, e:`{}`'.format( param, param_name, repr(value), type(value), format_exc(e)) logger.error(msg) raise ZatoException(msg=msg)
def __call__(self, req, initial_input_dict={}, initial_return_data={}, *args, **kwargs): """ Handles the request, taking care of common things and delegating control to the subclass for fetching this view-specific data. """ self.input_dict.clear() self.clear_user_message() try: super(CreateEdit, self).__call__(req, *args, **kwargs) self.set_input() input_dict = {'cluster_id': self.cluster_id} post_id = self.req.POST.get('id') if post_id: input_dict['id'] = post_id input_dict.update(initial_input_dict) for name in chain(self.SimpleIO.input_required, self.SimpleIO.input_optional): if name not in input_dict and name not in self.input_dict: input_dict[name] = self.input.get(name) self.input_dict.update(input_dict) logger.debug( 'Request input dict `%r` out of `%r`, `%r`, `%r`, `%r`, `%r`', self.input_dict, self.SimpleIO.input_required, self.SimpleIO.input_optional, self.input, self.req.GET, self.req.POST) response = self.req.zato.client.invoke(self.service_name, self.input_dict) if response.ok: return_data = { 'message': self.success_message(response.data) } return_data.update(initial_return_data) for name in chain(self.SimpleIO.output_optional, self.SimpleIO.output_required): if name not in initial_return_data: value = getattr(response.data, name, None) if value: if isinstance(value, basestring): value = value.encode('utf-8') else: value = str(value) return_data[name] = value self.post_process_return_data(return_data) return HttpResponse(dumps(return_data), mimetype='application/javascript') else: msg = 'response:[{}], details.response.details:[{}]'.format(response, response.details) logger.error(msg) raise ZatoException(msg=msg) except Exception, e: return HttpResponseServerError(format_exc(e))
def send_email(self, message): """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` or ``From`` headers. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ smtp_from = message['Return-Path'] or message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert len( from_rfc2822 ) == 1, "Malformed 'Return-Path' or 'From' address - it may only contain plain ASCII characters" smtp_from = from_rfc2822[0] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter( None, flatten( map(extract_rfc2822_addresses, [email_to, email_cc, email_bcc]))) assert smtp_to_list, "At least one valid recipient address should be specified for outgoing emails (To/Cc/Bcc)" try: message_id = message['Message-Id'] # Add email in Maildir if smtp_host contains maildir. if self.smtp_host.startswith('maildir:/'): from mailbox import Maildir maildir_path = self.smtp_host[8:] mdir = Maildir(maildir_path, factory=None, create=True) mdir.add(message.as_string(True)) return message_id try: self.conn.sendmail(smtp_from, smtp_to_list, message.as_string()) finally: try: # Close Connection of SMTP Server self.conn.quit() except Exception: # ignored, just a consequence of the previous exception pass except Exception, e: msg = "Mail delivery failed via SMTP server '%s'.\n%s: %s" % ( unicode(self.smtp_host), e.__class__.__name__, unicode(e)) raise ZatoException(self.cid, msg)
def invoke(self, target, *args, **kwargs): async_fallback, callback, callback_context, retry_repeats, retry_seconds, kwargs = self._get_retry_settings( target, **kwargs) # Let's invoke the service and find out if it works, maybe we don't need # to retry anything. kwargs['cid'] = kwargs.get('cid', new_cid()) try: result = self.invoking_service.invoke(target, *args, **kwargs) except Exception as e: msg = 'Could not invoke:`{}`, cid:`{}`, e:`{}`'.format( target, self.invoking_service.cid, format_exc()) logger.warn(msg) # How we handle the exception depends on whether the caller wants us # to block or prefers if we retry in background. if async_fallback: # .. invoke the background service and return CID to the caller. return self._invoke_async_retry(target, retry_repeats, retry_seconds, self.invoking_service.cid, kwargs['cid'], callback, callback_context, args, kwargs) # We are to block while repeating else: # Repeat the given number of times sleeping for as many seconds as we are told remaining = retry_repeats result = None while remaining > 1: try: result = self.invoking_service.invoke( target, *args, **kwargs) except Exception as e: msg = retry_failed_msg( (retry_repeats - remaining) + 1, retry_repeats, target, retry_seconds, self.invoking_service.cid, e) logger.info(msg) sleep(retry_seconds) remaining -= 1 # OK, give up now, there's nothing more we can do if not result: msg = retry_limit_reached_msg(retry_repeats, target, retry_seconds, self.invoking_service.cid) raise ZatoException(self.invoking_service.cid, msg) else: # All good, simply return the response return result
def validate_input_dict(cid, *validation_info): """ Checks that input belongs is one of allowed values. """ for key_name, key, source in validation_info: if not source.has(key): msg = 'Invalid {}:[{}]'.format(key_name, key) log_msg = '{} (attrs: {})'.format(msg, source.attrs) logger.warn(log_msg) raise ZatoException(cid, msg)
def invoke_async(self, name, payload='', channel=CHANNEL.INVOKE_ASYNC, data_format=DATA_FORMAT.DICT, transport=None, expiration=BROKER.DEFAULT_EXPIRATION, to_json_string=False, cid=None, callback=None, zato_ctx={}, environ={}): """ Invokes a service asynchronously by its name. """ if self.component_enabled_target_matcher: name, target = self.extract_target(name) zato_ctx['zato.request_ctx.target'] = target else: target = None # Let's first find out if the service can be invoked at all impl_name = self.server.service_store.name_to_impl_name[name] if self.component_enabled_invoke_matcher: if not self._worker_store.invoke_matcher.is_allowed(impl_name): raise ZatoException(self.cid, 'Service `{}` (impl_name) cannot be invoked'.format(impl_name)) if to_json_string: payload = dumps(payload) cid = cid or new_cid() # If there is any callback at all, we need to figure out its name because that's how it will be invoked by. if callback: # The same service if callback is self: callback = self.name else: sink = '{}-async-callback'.format(self.name) if sink in self.server.service_store.name_to_impl_name: callback = sink # Otherwise the callback must be a string pointing to the actual service to reply to so we don't need to do anything. msg = {} msg['action'] = SERVICE.PUBLISH.value msg['service'] = name msg['payload'] = payload msg['cid'] = cid msg['channel'] = channel msg['data_format'] = data_format msg['transport'] = transport msg['is_async'] = True msg['callback'] = callback msg['zato_ctx'] = zato_ctx msg['environ'] = environ # If we have a target we need to invoke all the servers # and these which are not able to handle the target will drop the message. (self.broker_client.publish if target else self.broker_client.invoke_async)(msg, expiration=expiration) return cid
def get_slices(self, orig_start, orig_stop): """ Slices the time range into a series of per-minute/-hour/-day/-month or -year statistics. """ slices = [] start = parse(orig_start) stop = parse(orig_stop) delta, result = self._get_slice_period_type(start, stop, orig_start, orig_stop) by_mins = result['by_mins'] by_hours_mins = result['by_hours_mins'] by_days_hours_mins = result['by_days_hours_mins'] by_months_days_hours_mins = result['by_months_days_hours_mins'] # Sanity check, find out whether more than one predicate is True. predicates = (by_mins, by_hours_mins, by_days_hours_mins, by_months_days_hours_mins) sum_preds = sum(int(elem) for elem in predicates) if sum_preds > 1: msg = 'sum:[{}] of predicates:[{}] is > 1, delta:[{}, {} {} {} {}], start:[{}], stop:[{}]'.format( sum_preds, predicates, delta, delta.years, delta.months, delta.days, delta.hours, start, stop) raise ZatoException(self.cid, msg) # We require that start and stop be at least that many minutes apart and, obviosuly, # that start lives farther in the past. if by_mins and delta.total_minutes < self.MINIMUM_DIFFERENCE: raise ValueError( 'stop and start must be at least [{}] minutes apart, start must be '\ 'farther in past; start:[{}], stop:[{}]'.format( self.MINIMUM_DIFFERENCE, orig_start, orig_stop)) if by_mins: # start=2012-10-23T20:13:00, stop=2012-10-23T21:07:00 slices.append(self.by_minutes(start, stop)) elif by_hours_mins: for slice in self._get_slices_by_hours(start, stop, delta): slices.append(slice) elif by_days_hours_mins or (by_months_days_hours_mins and delta.total_months == 1): for slice in self._get_slices_by_days(start, stop, delta): slices.append(slice) elif by_months_days_hours_mins: for slice in self._get_slices_by_months(start, stop, delta): slices.append(slice) else: for slice in self._get_slices_by_years(start, stop, delta): slices.append(slice) return slices
def remote_command_execute(req): """ Executes a command against the key/value DB. """ try: response = req.zato.client.invoke('zato.kvdb.remote-command.execute', {'command': req.POST['command']}) if response.has_data: return HttpResponse(dumps({'message': dumps(response.data.result)}), content_type='application/javascript') else: raise ZatoException(msg=response.details) except Exception, e: return HttpResponseServerError(format_exc(e))
def handle(self): conn_id = self.request.input.id patt_type = self.request.input.audit_repl_patt_type with closing(self.odb.session()) as session: conn = session.query(HTTPSOAP).\ filter(HTTPSOAP.id==conn_id).\ one() if not self.request.input.pattern_list: # OK, no patterns at all so we indiscriminately delete existing ones, if any, for the connection. self._clear_patterns(conn) session.commit() else: pattern_class = JSONPointer if patt_type == MSG_PATTERN_TYPE.JSON_POINTER.id else XPath conn_pattern_list_class = HTTSOAPAuditReplacePatternsJSONPointer if patt_type == MSG_PATTERN_TYPE.JSON_POINTER.id else \ HTTSOAPAuditReplacePatternsXPath all_patterns = session.query(pattern_class).\ filter(pattern_class.cluster_id==self.server.cluster_id).\ all() missing = set(self.request.input.pattern_list) - set( [elem.name for elem in all_patterns]) if missing: msg = 'Could not find one or more pattern(s) {}'.format( sorted(missing)) self.logger.warn(msg) raise ZatoException(self.cid, msg) # Clears but doesn't commit yet self._clear_patterns(conn) for name in self.request.input.pattern_list: for pattern in all_patterns: if name == pattern.name: item = conn_pattern_list_class() item.conn_id = conn.id item.pattern_id = pattern.id item.cluster_id = self.server.cluster_id session.add(item) session.commit() params = { 'action': CHANNEL.HTTP_SOAP_AUDIT_PATTERNS.value, 'id': conn_id, 'audit_repl_patt_type': self.request.input.audit_repl_patt_type, 'pattern_list': self.request.input.pattern_list, } self.broker_client.publish(params)
def create(req): try: response = req.zato.client.invoke('zato.http-soap.create', _get_edit_create_message(req.POST)) if response.has_data: return _edit_create_response(req, response.data.id, 'created', req.POST['transport'], req.POST['connection'], req.POST['name']) else: raise ZatoException(msg=response.details) except Exception: msg = 'Object could not be created, e:`{}`'.format(format_exc()) logger.error(msg) return HttpResponseServerError(msg)
def edit(req): try: response = req.zato.client.invoke('zato.http-soap.edit', _get_edit_create_message(req.POST, 'edit-')) if response.has_data: return _edit_create_response(req, response.data.id, 'updated', req.POST['transport'], req.POST['connection'], req.POST['edit-name']) else: raise ZatoException(msg=response.details) except Exception: msg = 'Update error, e:`{}`'.format(format_exc()) logger.error(msg) return HttpResponseServerError(msg)
def extract_target(self, name): """ Splits a service's name into name and target, if the latter is provided on input at all. """ # It can be either a name or a name followed by the target to invoke the service on, # i.e. 'myservice' or 'myservice@mytarget'. if '@' in name: name, target = name.split('@') if not target: raise ZatoException(self.cid, 'Target must not be empty in `{}`'.format(name)) else: target = '' return name, target