Package: it-helpdesk
it-helpdeskThis is an open-source, plaintext, email based automated IT helpdesk created for the EMPT IT suite. When hooked up to an email client, it takes piped in emails, parses them based on fully and easily customizable phrasebooks, and runs Ansible playbooks to accomplish typical IT duties like managing users. More and custom use cases can be added simply by creating an Ansible playbook and its matching phrasebook — no code needs to be touched.RequirementsAside from the Python dependencies that pip will install for you upon running the below installation, there are a few things that are needed for the helpdesk to work.A working Ansible setup with a Unix control node and some managed nodesA complete Inventory file for your Ansible installationA working mail server and client:This can be done with any email provider, or your own local server. If using an external providers services, you will need to set up a local mail client that can pull and pipe emails to scripts, like FDM or Postfix, and SMTP credentials to fetch and send mailPython version >3.10If you are using this with the EMPT IT suite, all of this will be preconfigured for you and won't need to be set up.InstallationThe it-helpdesk can be installed using pip. This will install all of its dependencies as well, if they are not already present in the install environment.pip3installit_helpdeskOnce installed, you can run the below command in the same environment to set up the necessary configuration files that the helpdesk will use.setup_helpdeskThis will bring up a CLI where you will enter the necessary information to be able to use the helpdesk, like directory paths and credentials. By default, the installer stores everything in an it-helpdesk directory inside the user's home directoryUsage/ExamplesAfter installing in the chosen directory, the relevant file structure will look like the following:.it-helpdesk
├──ansible
│├──help_templates
││├──manage_users_help.txt
││└──storage_help.txt
│├──inventory
│├──phrasebooks
││├──account_phrases.txt
││├──approved_commands.txt
││├──help_phrases.txt
││├──manage_account_phrases.txt
││├──manage_users_phrases.txt
││└──storage_phrases.txt
│├──playbooks
││├──help.yaml
││├──manage_users.yaml
││└──storage.yaml
│└──vars
│├──ansible.cfg
│└──it_helpdesk_config.yaml
└──mail_script.pyThe mail_script.py in the root of the directory is the script that calls the entire helpdesk software. Connect this to the desired email so that incoming emails are piped through the script for parsing and automation. I did this locally with fdm and my Gmail account as follows, sending to an interim bash script that activated the venv I was working in. It works the same with the Python script.action"inbox"maildir"~/Maildir/INBOX"action"piping"pipe"/Users/arnavsajith/Documents/Projects/EMPT/it-helpdesk/activate_venv.sh argv=%[mail_file]"account"my_email@gmail.com"imapsserver"imap.gmail.com"port993user"my_email@gmail.com"pass"my_smtp_password"new-onlycache"~/.imapcache"# Match all other mail and deliver using the 'inbox' action.# match all action "inbox"matchallaction"piping"and a simple bash script to pull from my Gmail#!/bin/shwhiletrue;dofdm-kmvvfetch2>&1|tee-a~/.fdm.logsleep5doneHowever you do it, once the piping works the helpdesk is online, and will parse all incoming emails to it for tasks to automate, assuming you have filled the inventory file with the addresses of the machines.Phrasebooks and keywordsPhrasebooks work in matched pairs with Ansible playbooks in order to define the information that needs to be in the email sent to the it-helpdesk for a task to complete. They can be as simple or complicated as you would like, as long as it matches the playbook and is formatted correctly it will work.PhrasebooksThis is how phrasebooks are formatted, taken from the aboveansible/phrasebooks/storage_phrases.txt*targets*
employee: user: username: account:
*selftargets*
my me myself i
*verbs_positive*
add more increase
*verbs_negative*
reduce decrease less
*queries*
'how much' left 'what is' 'have i' 'query'
*modifiers*
by to
*unit*
gbHow to use phrasebooksSections in the phrasebooks are separated by their labels within asterisks. These labels will be used when writing Ansible playbooks as well, so choose meaningful names for each section.Every section here aside from*targets*and*selftargets*sections are completely optional. These search for matching phrases for each section in the email, and if found, creates a True/False flag applying to the section. For example, an email body snippet ofIncrease my storage allocation by 5gbwould give{verbs_positive: True, verbs_negative: False, queries: False, selftargets: True, modifiers: by, unit: gb}These are then used in the Ansible playbook to decide what the email is asking to be done.
The*targets* , *modifiers*, and *unit*flags are unique. The*modifiers* and *unit*flags are unique and have coded exceptions for them that parse anything in the format ofaction amount unitlike for increasing/decreasing storage. However, this means that it will as such rarely be used, and when needed can be implemented like this.The*targets*flag is the only flag that can get values for variables that might be needed for your Ansible playbook. It searches the email foreachof its phrases, and if it finds any, captures the next token and stores it as a key-value pair for that phrase. This allows for more complex tasks that cannot be accomplished with just True/False flags. The snippet:Increase the storage allocation for the user: alicesmith to 3.5gbwould give{targets: alicesmith, verbs_positive: True, verbs_negative: False, queries: False, selftargets: True, modifiers: to, unit: gb}The first target in the phrasebook will always occupy thetargets: valuerole. If additional targets are searched for, they will be stored intarget_name: target_valuethat can be accessed in ansible with theirtarget_name. For example, if you have the targetsusername: password: name:as your desired information, the snippetusername: john password: 1234 and name: johnathanwould store as{targets: john, password: 1234, name: johnathan}along with whatever other flags you set to search for in the phrasebook.KeywordsThe phrasebook used to parse the email is determined without having to search all of the phrasebooks and finding matches by the use of a separate, but linked, keyword file. This contains a few words/phrases that have to exist in thesubjectof the email in order to cut down on parsing time for efficiency. There is a single keyword file that contains all of the keywords for every playbook and phrasebook that exists, and the keywords must be unique. When a match is found, it is looked up in theit_helpdesk_config.yaml's request directory for reference and organization.
Default.keywords.txtfile:*help*
documentation help
*storage*
storage space quota
*manage_account*
username permissions password 'change username' 
*query_account*
'query account'
*manage_users*
new 'new user' 'new employee' onboarding delete 'delete user' remove 'add user'requests_directory: {1: 'help',
                     2: 'storage',
                     3: 'manage_account', 
                     4: 'query_account',
                     5: 'manage_users',
                     }How to use keywordsThe keywords file functions similarly to the phrasebooks. It flags the sections True/False if any of its keywords are found in the email subject, and returns the request type after looking it up in theit_helpdesk_config.yaml's request directory. For example, if the subject of the email isIncrease Storage Quota, it will flagstorageas True, and returnrequest_type: 2to the helpdesk so it can start the parsing. The order of entries in the.keywords.txtfile has to match therequests_directoryin order for the system to work.Naming conventionsWhen adding new automation capabilities to the helpdesk by creating new playbooks and phrasebooks, a few naming conventions must be adhered to. Beyond that, as long as they match each other, they will link and whatever functionality you add will work in the helpdesk.When creating a new capability for the desk, it must hold to the following:Playbook:{playbook_task}.yamlPhrasebook:{playbook_task}_phrases.yamlKeyword Line*playbook_task*Help file:{playbook_task}_help.txtRequests directory:id: '{playbook_task}'From the above directory, we have the following example:Playbook:manage_users.yamlPhrasebook:manage_users_phrases.yamlKeyword Line*manage_users*Help file:manage_users_help.txtRequests_directory:5: 'manage_users'The it_helpdesk_config fileThe it_helpdesk_config file is generated when you run thesetup_helpdeskcommand for the first time alongside the rest of the files. It is populated with your responses for information that the helpdesk needs to accomplish its tasks. The helpdesk will not work without having this config file, and at least thehelpdesk_dirneeds to be filled out to the location of theit-helpdeskdirectory. If moving the directory, ensure that the config file is changed to match, or it will search the old location.Any configurations, settings, or saved information that is repeatedly used by the helpdesk should be stored here, with a variable name that can be called from within the playbooks when needed. If you add any new playbooks, ensure that you add it to therequests_directorywithin this file as well.If you want to create additional config files, it will work as long as you load them into your Ansible playbooks as well. Just make sure to keep thehelpdesk_dirandrequests_directoryin the original file, updated for all changes.Help filesHelp files are.txtdocuments that go in the/help_templatesdirectory with a matching name to their playbook/phrasebook. These get automatically sent to users who send an email containinghelp with: {{ functionality }}, as long as the name matches. It is beneficial to add an error message with a basic reply of how to send a help message likeIf you need help with this functionality, send an email with the subject: Help and body: help with: manage_usersOnce they send the email, they will quickly receive a reply whos body is the{playbook_task}_help.txtThemanage_users_help.txtlooks like this:Here is an exemplar of how to use the manage users function of the IT-Helpdesk to create and delete users in your organization. Any words within quotes should be replaced with your desired values, WITHOUT the quotes.

Creating Users:

Subject: New User
Body:
I'd like to create a new user with the following information:
username: 'desired username'
password: 'desired password'
first_name: 'employee first name'
last_name: 'employee last name'


Deleting Users:

Subject: Delete User
Body:
I'd like to delete the account with the username: 'desired account to delete'This allows the user to quickly copy and paste the template and fill in their values if they were struggling beforehand.Making playbooksMaking playbooks is much too complicated to give a complete overview of here, but Ansible can be used to basically automate any IT tasks. It has support for a variety of plugins and capabilities, and is basically English as well. It is extremely beginner friendly. For an example of how an Ansible playbook can be made/used, check the below playbook snippet of user storage allocation.vars:
    ansible_user: ansible

    undefined_variables: []

    request_amount: "{{ amount | float}}"

    request_unit: "gb"

    request_action: "{{ 'increase' if (verbs_positive|bool == True) else 'decrease'}}"

    request_net_change: "{{ request_amount if request_action == 'increase' else request_amount * -1 }}"

    current_quota: '{{ (ansible_zfs_datasets[0].reservation | replace("G", "")) | float}}'

    increase_amount: '{{(current_quota|float + request_net_change|float) if modifiers == "by" else request_amount|float }}'

  vars_files:
    - ../vars/shared_vars.yaml

  tasks:
    - name: "Send email notifying of invalid request"
      community.general.mail:
              host: '{{ mail_server }}'
              port: '{{ mail_port }}'
              secure: always
              username: '{{ helpdesk_email }}'
              password: '{{ helpdesk_password }}'
              to: '{{ from }}'
              from: '{{ helpdesk_email }}'
              subject: "Could not execute your recent user management request"
              body: "We couldn't understand what you wanted from your previous user management request. Please ensure that all necessary information is included. Send an email with the subject: Help and body: 'help with: manage_users' to see how to properly format your request.'"
      when: verbs_positive == None and verbs_negative == None and queries == None

    - name: "Exit playbook run if invalid request"
      ansible.builtin.fail:
        msg: "Invalid request"
      when: verbs_positive == None and verbs_negative == None and queries == None

    - name: User Storage Query
      community.general.zfs_facts:
        dataset: 'zroot/empt/homes/{{ targets }}'
      register: zfs_query
      ignore_errors: true

    - name: "Send email notifying if target username is undefined"
      community.general.mail:
        host: '{{ mail_server }}'
        port: '{{ mail_port }}'
        secure: always
        username: '{{ helpdesk_email }}'
        password: '{{ helpdesk_password }}'
        to: '{{ from }}'
        from: '{{ helpdesk_email }}'
        subject: "Could not execute your recent user management request"
        body: "The username provided: {{ targets }} is not a valid user. Please ensure to include a user with the format 'username: targeted_username', and that the user exists in your organization."
      when: targets == None or zfs_query is failed

    - name: "Exit playbook run if no username is provided"
      ansible.builtin.fail:
        msg: "A username was not provided in the email request"
      when: targets == None or zfs_query is failedAuthorsGithubLinkedInLicenseMITMIT License

Copyright (c) 2023 Arnav-Sajith

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.```