Skip to content
osuosl-cookbooksPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

osl-rt

Requirements

Platforms

  • AlmaLinux 8, 9 (Request Tracker 4.4)
  • AlmaLinux 10 (Request Tracker 5)

The RT major version follows the platform: EL8/9 install RT 4.4, EL10 installs RT 5. The cookbook adjusts automatically — notably, extensions that RT 5 merged into core (RT::Extension::REST2, RT::Authen::Token) are skipped from the plugins list on EL10 (loading them as plugins makes RT 5 fail to start).

Cookbooks

TLS / reverse proxy

By default this cookbook serves RT over plain HTTP only. TLS is expected to be terminated by an upstream HAProxy (or similar) reverse proxy that forwards to this backend over HTTP. Apache is configured with osl-apache::mod_remoteip so the real client IP is recovered from the X-Forwarded-For header.

To terminate TLS on the RT host instead, set ssl-certificate to the id of an item in the certificates data bag. The cookbook then installs it with certificate_manage, listens on 443 and redirects port 80 to HTTPS. Requests for internal-domain are not redirected, because rt-mailgate and the rt CLI post to http://<internal-domain>.

osl-apache reads its listen attribute while recipes compile. So the resource sets listen, and the workers-per-cpu limits, when it is declared, not when it converges. It includes osl-apache, osl-apache::mod_remoteip and osl-apache::mod_perl at the same point, so Apache is installed before the resource's action runs. Declare it before any recipe in the run list that includes osl-apache. If osl-apache has already been loaded without the ports this site needs, the resource raises an error at compile time. A wrapper that can't change the order can set node['osl-apache']['listen'] itself first.

The list of trusted proxies defaults to OSUOSL's load balancers. For other deployments, override it on the node:

node.default['osl-apache']['mod_remoteip']['trusted_proxy'] = %w(10.0.0.1)

SELinux

RT's SELinux policy ships in the OSL request-tracker-selinux RPM, which this cookbook installs alongside request-tracker:

  • the request_tracker module
  • /opt/rt/var labelled httpd_sys_rw_content_t
  • the httpd_can_sendmail and httpd_can_network_connect_db booleans

The cookbook sets no policy of its own. The kitchen suites converge with osl-selinux enforcing and fail on any httpd_t or procmail_t denial.

Usage

osl-rt is resource-first: declare the osl_request_tracker resource. The resource name is the site's fqdn; the rest of the configuration lives in the request-tracker data bag (selected with data_bag). Do NOT put configuration in node attributes.

# Deploy RT for requests.openpowerfoundation.org, reading the rest of the
# config from request-tracker/requests.
osl_request_tracker 'requests.openpowerfoundation.org' do
  data_bag 'requests'
end

Data Bag Attributes

Name Type Description Default
db-username String The username of the DB user nil
db-password String The password of the DB user nil
root-password String The password used for the root account on RT nil
fqdn String Set by the osl_request_tracker resource name, not the data bag (any fqdn key here is ignored). The site's web/host domain. resource name
mail-domain String The public email domain for queue addresses, when it differs from the host fqdn (e.g. example.org while the site is support.example.org). Queue mail at either domain is delivered to RT; other addresses at mail-domain aren't local and go out through the relay. fqdn
web-port Integer Sets RT's $WebPort. Needed when TLS terminates upstream (e.g. HAProxy) and RT serves plain HTTP: set 443 so RT treats itself as HTTPS, otherwise it assumes http://<fqdn>:80 and rejects HTTPS form posts with a "possible cross-site request forgery" error. RT default (80)
web-base-url String Sets RT's $WebBaseURL explicitly. Only needed when the public URL isn't derivable from fqdn + web-port (a different public host, a WebPath prefix, etc.); otherwise RT derives it. derived
user String The user account that is responsible for being the default email support
failed-email String Address that mail RT fails to process is forwarded to root
logo Hash Optional custom branding. url is fetched into RT's static images dir and $LogoURL is set to the served path; link/alt set $LogoLinkURL/$LogoAltText. Assumes the default (empty) WebPath; override $LogoURL via extra-config otherwise. nil
internal-domain String A workaround required needs a non-sublevel domain name to access the site internally rtlocal
db.type String The database engine, passed to RT as $DatabaseType. Use mysql for MySQL/MariaDB or Pg for PostgreSQL. With Pg the cookbook installs the perl-DBD-Pg driver and the psql client (used by the one-time DB guards) instead of the MariaDB client. mysql
db.host String The hostname of the DB server localhost
db.name String The DB name on the DB server rt
db-upgrade String Opt-in: the RT version the database is currently at (e.g. "4.4.7"), passed as --upgrade-from to apply pending schema upgrades (after importing a DB or an RT package upgrade). The "proceed?" prompt is auto-confirmed, so back up first. See docs/migration.md. unset
queues Hash The queues and emails available for RT. The key is the pretty print, and the value is a email-valid name. {'Support Example': nil} Any nil-valued key will be ignored.
spam-exempt Array Queue emails whose mail is never diverted to .Spam/ by procmail's X-Spam-Status rule. Abuse-type queues need this: their reports quote the very spam they report, so they tag as spam by nature but must still be ticketed. the queues emails intersected with abuse/postmaster
plugins Array A list of plugins to add to the RT site. On EL10/RT 5, extensions merged into core (RT::Extension::REST2, RT::Authen::Token) are automatically skipped. []
lifecycles Hash Any custom lifecycles to make available in RT. Arbitrary lifecycles (including an approvals lifecycle) are emitted verbatim, so add them here rather than in code. {} Provides default lifecycle.
extra-config Hash Raw RT config options emitted verbatim into RT_SiteConfig.pm. Keys must be valid RT names (e.g. $Timezone, $DefaultQueue, $ParseNewMessageForTicketCcs). String values are quoted; numbers/literals are emitted as-is; keys beginning with % are treated as Perl literals (e.g. %FullTextSearch). Do not set _Plugins/_Lifecycles here — use plugins/lifecycles. The cookbook also sets %ReferrerComponents so a link to /Search/Bulk.html that carries only a search (Query and Rows) opens without RT's "possible cross-site request forgery" warning, even from a page that sends no Referer; a link that also carries an update or display options (Format, OrderBy) is still checked. A %ReferrerComponents here replaces it. {}
ssl-certificate String Opt-in: serve TLS on the RT host with this item from the certificates data bag (installed as <id>.pem, <id>.key and <id>-bundle.crt under /etc/pki/tls). Apache listens on 443 and port 80 redirects to HTTPS, except for internal-domain. Set web-port to 443 as well. unset (HTTP only)
workers-per-cpu Integer Opt-in: cap Apache prefork workers at this many per CPU core. It is never fewer than 5 and never more than osl-apache's memory-based limit. Every worker is a full RT interpreter, so on a CPU-bound host more workers only add contention. 3 is a good start. unset (osl-apache sizes by memory)
clean-sessions String Age for a daily rt-clean-sessions --older <age> --skip-user cron (/etc/cron.d/rt-clean-sessions, 03:15, as apache), in RT's <NUM>[H|D|M|Y] format. RT never expires sessions itself. --skip-user keeps users logged in on more than one browser. Set false to remove the cron. 30D
fulltext-index Boolean Opt-in: sets %FullTextSearch to Indexed => 1 with RT's default index table (AttachmentsIndex, plus the ContentIndex column on Pg), and adds a rt-fulltext-indexer --quiet cron every 10 minutes. The index must exist first: run /opt/rt/sbin/rt-setup-fulltext-index --dba <db-username> once, off-peak and inside tmux or screen, before turning this on. --dba is needed because the script otherwise connects as RT's default admin user (root, or postgres on Pg); it prompts for that user's password, so keep the password off the command line. On MySQL, answer mysql for the index type and keep the default table name, which this key expects. Ignore the %FullTextSearch block it prints at the end, since this key sets it. It tokenizes every attachment and drops any existing index table, so never rerun it on a live index. On MySQL, RT 4.4 can't index attachments containing 4-byte UTF-8 characters such as emoji, because it connects as utf8mb3; the indexer warns and skips them, so content search can't find them. RT 5 uses utf8mb4. RT checks for the table only when it starts: if httpd started while the table was missing, full-text search stays off until httpd restarts. Restart httpd after the converge that turns this on. A %FullTextSearch in extra-config overrides this setting. false
spam-digest Array Addresses that get a daily, headers-only digest of the mail procmail filed into .Spam and .AutoReply under the user's ~/Mail in the last 24 hours, newest first, at most 200 per folder. The digest lists the date, file name, From, X-Original-To, Subject and the spam score (or why the message was filed), and never reads a message body. /usr/local/sbin/rt-spam-digest sends it as postmaster@<node fqdn> from the rt-spam-digest service, run as user. The rt-spam-digest.timer fires at 06:00 Pacific, within 5 minutes, and the times in the digest are Pacific. Runs are kept 24 hours apart, so no message is missed; on the two DST change days the gap is 23 or 25 hours, so the 23-hour day can list an hour of mail twice and the 25-hour day can miss an hour. The digest is mailed even when there is nothing to report, so a day with no digest means it is broken. The Lab's daily triage (spamwatch.py) parses the body. Run rt-spam-digest --stdout --fqdn <name> as user to print it instead. Set false to remove the timer, service and script. ["ramereth@osuosl.org"]

Example Data Bag Attributes

{
  "db": {
    "type": "mysql",
    "host": "localhost",
    "name": "rt"
  },
  "mail-domain": "example.org",
  "user": "support",
  "failed-email": "systems@example.org",
  "logo": {
    "url": "https://example.org/img/logo.png",
    "link": "https://support.example.org/",
    "alt": "Example Support"
  },
  "queues": {
    "Support": "support",
    "Frontend Team": "frontend",
    "Backend Team": "backend",
    "DevOps Team": "devops",
    "Marketing Team": "advertising",
    "The Board Of Directors": "board"
  },
  "plugins": ["RT::Extension::REST2", "RT::Authen::Token"],
  "extra-config": {
    "$Timezone": "US/Pacific",
    "$DefaultQueue": "Support",
    "$ParseNewMessageForTicketCcs": 1,
    "%FullTextSearch": "Enable => 1, Indexed => 1"
  },
  "lifecycles": {
    "new-wave": {
      "initial": ["order in"],
      "active": ["order work", "order delayed"],
      "inactive": ["order up"]

      "transitions": {
        "": ["order in"],
        "order in": ["order work"],
        "order work": ["order delayed", "order up"],
        "order delayed": ["order work"]
      },
      
      "rights": {
        "* => order in": "ResetOrder"
      }
    }
  }
}

Migration / importing an existing instance

The recipe is safe to converge against an already-populated database: schema init, the root password, and existing queues are all guarded by the actual database state, so an imported instance is never re-initialized or clobbered. The opt-in db-upgrade key applies pending schema upgrades after an import or package upgrade. See docs/migration.md for the full details, the migration Test Kitchen suite, and how to generate the seed dump.

Resources

osl_request_tracker

Deploys an RT web service on the node (Apache + RT, the database schema, procmail, and a osl_postfix_server 'default' mail server). The resource name is the site's fqdn; the rest of the config comes from a request-tracker data bag item (see Data Bag Attributes).

Property Type Description Default
fqdn String The site's fqdn (the resource name). Authoritative — overrides any fqdn in the data bag. resource name
data_bag String Name of the item in the request-tracker data bag holding the rest of the config. default
osl_request_tracker 'requests.openpowerfoundation.org' do
  data_bag 'requests'
end

Testing unpublished request-tracker RPMs

To converge against request-tracker RPMs built in rpms/request-tracker before they're published, run make repo there, then set OSL_RT_LOCAL_REPO for kitchen with the openstack driver:

OSL_RT_LOCAL_REPO=1 kitchen test two-domain-almalinux-9

A pre_converge hook in kitchen.openstack.yml rsyncs REPO/<release> (from ~/git/osl/rpms/request-tracker, or OSL_RT_REPO) to the instance. It then installs its request-tracker-local.repo, whose priority=1 wins over the published repo. Without a build it prints a note and the published RPMs are used. Start from fresh instances, because the resource installs RT but never upgrades it.

Contributing

  1. Fork the repository on Github
  2. Create a named feature branch (like username/add_component_x)
  3. Write tests for your change
  4. Write your change
  5. Run the tests, ensuring they all pass
  6. Submit a Pull Request using Github

License and Authors

Copyright:: 2023, Oregon State University

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages