예제 #1
0
 def rt_client_session(self):
     # This method is made public to make it possible to operate
     # on an `rt.Rt` instance directly. However, if possible, it
     # is recommended to use other `RTClientAPI`'s public methods
     # rather than this one.
     if not self._config['active']:
         raise RuntimeError('RT is turn off in the configuration '
                            '(i.e., the `active` option is false)')
     rest_api_url = self._config['rest_api_url']
     username = self._config['username']
     try:
         rt = Rt(url=rest_api_url)
         if not rt.login(login=username, password=self._config['password']):
             raise RTClientAPIError('could not log in to RT')
         try:
             yield rt
         finally:
             self._try_logout(rt)
     except (RtError, RTClientAPIError) as exc:
         raise RTClientAPIError('RT-related error - {} ('
                                'config option {}: {!r}; '
                                'config option {}: {!r})'.format(
                                    make_exc_ascii_str(exc),
                                    self._repr_opt_name('rest_api_url'),
                                    rest_api_url,
                                    self._repr_opt_name('username'),
                                    username))
    def connect(self, timeout=60):

        if not self._config:
            print("Making dummy connection - all operations will be no-ops.", file=sys.stderr)
            return self

        self.server_path = self._config['server']
        self.username, self.password = self._config['user'], self._config['pass']
        self._queue = self._config[self._queue_setting]

        self.tracker = Rt( '/'.join([self.server_path, 'REST', '1.0']),
                           self.username,
                           self.password,
                           default_queue = self._queue )

        if not self.tracker.login():
            raise AuthorizationError('login() failed on {_config_name} ({tracker.url})'.format(**vars(self)))

        # Here comes the big monkey-patch-o-doom!
        # It will force a 60-second timeout on the Rt session, assuming the internal implementation
        # of session is not changed in the requests library.
        from types import MethodType
        foo = self.tracker.session
        foo._merge_environment_settings = foo.merge_environment_settings
        foo.merge_environment_settings = MethodType(
                lambda s, *a: dict([*s._merge_environment_settings(*a).items(), ('timeout', s.timeout)]),
                foo )
        foo.timeout = timeout
        # End of monkey business

        return self
예제 #3
0
def get_instance():
    """Make a RT instance and return it."""
    url = current_app.config.get("CFG_BIBCATALOG_SYSTEM_RT_URL", "")
    login = current_app.config.get("CFG_BIBCATALOG_SYSTEM_RT_DEFAULT_USER", "")
    password = current_app.config.get("CFG_BIBCATALOG_SYSTEM_RT_DEFAULT_PWD", "")

    if url:
        tracker = Rt(
            url=url,
            default_login=login,
            default_password=password,
        )
        tracker.login()
        return tracker
예제 #4
0
def get_instance():
    """Make a RT instance and return it."""
    url = current_app.config.get("CFG_BIBCATALOG_SYSTEM_RT_URL", "")
    login = current_app.config.get("CFG_BIBCATALOG_SYSTEM_RT_DEFAULT_USER", "")
    password = current_app.config.get("CFG_BIBCATALOG_SYSTEM_RT_DEFAULT_PWD",
                                      "")

    if url:
        tracker = Rt(
            url=url,
            default_login=login,
            default_password=password,
        )
        tracker.login()
        return tracker
class RTManager():
    def __init__(self, config_name, queue_setting):
        """Communication with RT is managed via the RT module.
           This wrapper picks up connection params from an .ini file,
           which must exist before you can even instatiate the object.

           To actually connect, either call connect() explicitly or say:
             with RTManager('test-rt') as rt_conn:
                ...
           to connect implicitly.
        """
        self._config_name = config_name
        self._queue_setting = queue_setting + '_queue' # eg. pbrun_queue, run_queue
        if config_name.lower() == 'none':
            # Special case for short-circuiting RT entirely, whatever the .ini
            # file says.
            self._config = None
        else:
            self._config = self._get_config_from_ini(config_name)

        self.tracker = None

    def connect(self, timeout=60):

        if not self._config:
            print("Making dummy connection - all operations will be no-ops.", file=sys.stderr)
            return self

        self.server_path = self._config['server']
        self.username, self.password = self._config['user'], self._config['pass']
        self._queue = self._config[self._queue_setting]

        self.tracker = Rt( '/'.join([self.server_path, 'REST', '1.0']),
                           self.username,
                           self.password,
                           default_queue = self._queue )

        if not self.tracker.login():
            raise AuthorizationError('login() failed on {_config_name} ({tracker.url})'.format(**vars(self)))

        # Here comes the big monkey-patch-o-doom!
        # It will force a 60-second timeout on the Rt session, assuming the internal implementation
        # of session is not changed in the requests library.
        from types import MethodType
        foo = self.tracker.session
        foo._merge_environment_settings = foo.merge_environment_settings
        foo.merge_environment_settings = MethodType(
                lambda s, *a: dict([*s._merge_environment_settings(*a).items(), ('timeout', s.timeout)]),
                foo )
        foo.timeout = timeout
        # End of monkey business

        return self

    # Allow us to use this in a 'with' clause.
    def __enter__(self):
        return self.connect()
    def __exit__(self, *exc):
        # Can you logout of RT? Do you want to?
        pass

    def _get_config_from_ini(self, section_name):

        # Either read the config pointed to by RT_SETTINGS or else the default.
        # Don't attempt to read both, even though ConfigParser supports it.
        file_name = os.environ.get('RT_SETTINGS')
        file_name = file_name or os.path.join(os.path.expanduser('~'), '.rt_settings')

        cp = configparser.ConfigParser()
        if not cp.read(file_name):
            raise AuthorizationError('unable to read configuration file {file_name}'.format(**locals()))

        # A little validation
        if section_name not in cp:
            raise AuthorizationError('file {file_name} contains no configuration section {section_name}'.format(**locals()))

        conf_section = cp[section_name]

        # A little more validation
        if not all([conf_section.get(x) for x in ['server', 'user', 'pass', self._queue_setting]]):
            raise AuthorizationError('file {file_name} did not contain all settings needed for RT authentication'.format(**locals()))

        return conf_section


    # Added for illuminatus, adapted for SMRTino
    def find_or_create_run_ticket(self, run_id, subject, text=None):
        """Create a ticket for run if it does not exist already.
           If text is specified it will be used as the request blurb for
           the new ticket but if the ticket already existed it will be
           ignored.
           Returns a pair (ticket_id, created?).
        """
        c = self._config
        ticket_id, _ = self.search_run_ticket(run_id)

        if ticket_id:
            return ticket_id, False

        # Since dummy mode returns 999, if ticket_id was unset we can infer we have a real
        # connection and proceed with real ops.

        # Text munge
        text = re.sub(r'\n', r'\n      ', text.rstrip()) if text \
               else ""

        ticket_id = int(self.tracker.create_ticket(
                Subject   = subject,
                Queue     = self._queue,
                Requestor = c['requestor'],
                Cc        = c.get('run_cc'),
                Text      = text or ""      ))

        # Open the ticket, or we'll not find it again.
        self.tracker.edit_ticket(ticket_id, Status='open')
        return ticket_id, True

    def search_run_ticket(self, run_id):
        """Search for a ticket referencing this run, and return the ticket number,
           as an integer, along with the ticket metadata as a dict,
           or return (None, None) if there is no such ticket.
        """
        c = self._config
        if not c:
            #In dummy mode, all tickets are 999
            return (999, dict())

        # Note - if the tickets aren't opened then 'new' tickets will just pile up in RT,
        # but I don't think that should happen.
        tickets = list(self.tracker.search( Queue = self._queue,
                                            Subject__like = '%{}%'.format(run_id),
                                            Status = 'open'
                                          ))

        if not tickets:
            return (None, None)

        # Order the tickets by tid and get the highest one
        def get_id(t): return int(t.get('id').strip('ticket/'))
        tickets.sort(key=get_id, reverse=True)
        tid = get_id(tickets[0])

        if len(tickets) > 1:
            # Should use really use proper logging here
            print("Warning: We have {} open tickets for run {}! Using the latest, {}".format(
                                    len(tickets),           run_id,               tid), file=sys.stderr)

        #Failing that...
        return (tid, tickets[0]) if tid > 0 else (None, None)

    def reply_to_ticket(self, ticket_id, message, subject=None):
        """Sends a reply to the ticket.
        """
        if subject:
            # The rest API does not support supplying a subject, but I can maybe
            # hack around this? No, not easily.
            raise NotImplementedError("RT REST API does not support setting subjects on replies.")

        # Dummy connection mode...
        if not self._config: return True

        return self.tracker.reply(ticket_id, text=message)

    def comment_on_ticket(self, ticket_id, message, subject=None):

        if subject:
            #The rest API does not support supplying a subject, but I can maybe
            #hack around this? No, not easily.
            raise NotImplementedError("RT REST API does not support setting subjects on replies.")

        # Dummy connection mode...
        if not self._config: return True

        return self.tracker.comment(ticket_id, text=message)

    def change_ticket_status(self, ticket_id, status):
        # Dummy connection mode...
        if not self._config: return

        kwargs = dict( Status = status )
        # Ignore IndexError raised when subject is already set
        with suppress(IndexError):
            self.tracker.edit_ticket(ticket_id, **kwargs)

    def change_ticket_subject(self, ticket_id, subject):
        """You can reply to a ticket with a one-off subject, but not via the
           REST interface, which fundamentally does not support this.
           (see share/html/REST/1.0/Forms/ticket/comment in the RT source code)
           This call permanently changes the ticket subject.
        """
        # Dummy connection mode...
        if not self._config: return

        # why the extra space?? I'm not sure but it looks to have been added deliberately.
        kwargs = dict( Subject = "{} ".format(subject) )

        # Ignore IndexError raised when subject is already set
        with suppress(IndexError):
            self.tracker.edit_ticket(ticket_id, **kwargs)
예제 #6
0
    def create_rt_ticket(self, observable):
        # create an observable config item that will be used to contain all observable and template info
        # to pass along to RT during ticket creation
        obs_config = RT4ResponderConfig(weight='case', **self.config)
        obs_config.update(weight='observable', **observable)
        # defang indicators and write them back as a single string joined together by newlines
        if 'indicator_list' in observable:
            indicator_list = defang(u'\n'.join(observable['indicator_list']))
            observable.update(weight='observable',
                              **{'indicator_list': indicator_list})
        else:
            self.error("""Unable to find indicators on case/alert/observable: 
                {}""".format(json.dumps(observable, indent=1)))

        if 'template' in observable:
            obs_config.update(weight='observable',
                              **{'template': observable['template']})
        if 'template' not in obs_config:
            self.error("""
                Couldn't map a tag to a notification type. 
                Observable/alert/case must be tagged with one 'rt4_set_template:<template_name>' tag, 
                where <template_name> is the name of a file (without .j2 ext) in /templates dir"""
                       )
        # render the notification template to be passed on to the observable config item
        rendered_template = NotificationContext().render_blocks_to_dict(
            template_name=obs_config['template'], kwargs=observable)
        obs_config.update(weight='template', **rendered_template)

        if 'Requestor' in observable:
            obs_config.update(weight='observable',
                              **{'Requestor': observable['Requestor']})
        if 'Requestor' not in obs_config:
            self.error("""
                Case/alert/observable must be tagged with at least one 'contact:[email protected]' or 
                set_rt4_requestor:[email protected] tag with an appropriate email address"""
                       )

        # build session dict
        rt_session = {
            'url': self.server + "/REST/1.0/",
            'default_login': self.username,
            'default_password': self.password
        }

        # create ticket dict
        rt_ticket = {}

        # add additional k,v pairs (as long as it's not the template or indicator_list since those are not accepted
        # as params to the Rt py module for RT ticket creation)
        for key, value in obs_config.items():
            if obs_config[
                    key] is not None and key != 'indicator_list' and key != 'template':
                rt_ticket[key] = value

        # create rt session
        try:
            rt_session = Rt(**rt_session)
            login_ret = rt_session.login()
        except ConnectionError as e:
            self.error("{}".format(e))
        except Exception as e:
            self.error("Error: {}".format(e))
        if login_ret != True:
            self.error('Authentication/Connection error to RT')

        # create ticket
        try:
            new_ticket = rt_session.create_ticket(**rt_ticket)
        except Exception as e:
            rt_session.logout()
            self.error(
                """RT ticket creation error: {} Possibly bad data such as non-existent Owner or Queue; 
            or data that does not correspond to an RT field. 
            \nSent the following RT request: {}""".format(
                    e, json.dumps(rt_ticket, indent=2)))

        rt_session.logout()
        return new_ticket, rt_ticket
예제 #7
0
        if user:
            kwargs["on_behalf_of"] = user
        ZAMMADS[user] = ZammadAPI(
            host=config["zammad_host"],
            username=config["zammad_user"],
            password=config["zammad_password"],
            is_secure=config["zammad_secure"],
            **kwargs,
        )
    return ZAMMADS[user]


target = get_zammad()
target.user.me()

source = Rt(config["rt_url"], config["rt_user"], config["rt_pass"])
if not source.login():
    print("Failed to login to RT!")
    sys.exit(2)

if os.path.exists("rt2zammad.cache"):
    # Load RT from cache
    with open("rt2zammad.cache", "rb") as handle:
        data = pickle.load(handle)
    users = data["users"]
    queues = data["queues"]
    tickets = data["tickets"]
    attachments = data["attachments"]

else:
    # Load RT from remote
예제 #8
0
파일: main.py 프로젝트: hrdrq/reading_tool
# -*- coding: utf-8 -*-

import sys
from PyQt5.QtWidgets import QApplication

from rt import Rt
from rt.article import Article

if __name__ == '__main__':
    app = QApplication(sys.argv)
    rt = Rt()
    rt.show()
    sys.exit(app.exec_())

    # a = Article()
    # print(a.list())

    # a = Article()
    # print(a.item('123'))
예제 #9
0
 def tree(self, test_no):
     tree = Rt(self.provider)
     return tree.test(test_no)
예제 #10
0
 def get_tracker(self):
     return Rt(settings.RT_HOST,
               settings.RT_UN,
               settings.RT_PW,
               http_auth=HTTPBasicAuth(settings.RT_UN, settings.RT_PW))