TrueNAS Core Nextcloud 23.0.2 Plugin update -> 27.0.2

A nextcloud plugin in a TrueNAS Core system that hadn’t been updated is well, a problem. If you update the Plugin it will go straight to Nextcloud 27 which well you can’t do an update like that. So here’s what we did.

Update to the latest version of 23 in the web browser and proceed with this until you get to version 25. You will notice that you cannot get past here if you’re on a Jail running 12.2 because it has PHP74 installed by default with the original Nextcloud package.

After this point you have to install PHP 8. But doing so will try and remove nextcloud-php74 package which would remove Nextcloud of course and kinda make the whole thing pointless so, we need to force that to remain installed while we gut PHP and reinstall PHP 8.

Lock the nextcloud package, we don’t want to remove it.

pkg lock nextcloud-php74

Install PHP80

pkg install php80-bcmath php80-bz2 php80-ctype php80-curl php80-dom php80-exif php80-fileinfo php80-filter php80-gd php80-gmp php80-iconv php80-intl php80-ldap php80-mbstring php80-opcache php80-pcntl php80-pcntl php80-pdo_mysql php80-pecl-APCu php80-pecl-imagick php80-pecl-redis php80-posix php80-session php80-simplexml php80-xmlreader php80-xmlwriter php80-xsl php80-zip php80-zlib

Restart FPM to reload the web UI:
/usr/local/etc/rc.d/php-fpm restart

Perform the update through to v27 from the Web UI.

Update the plugin in TrueNAS Core once the web UI update completes. THIS WILL FAIL.

Once it fails, log back into the console and manually uninstall/install the following:

pkg unlock nextcloud-php74
pkg remove nextcloud-php74-23.0.2
pkg install nextcloud-php80 nginx mysql80-server redis php80-pecl-redis wget rsync

Now, the included nextcloud version is 27.0.0 and we’re already above that and downgrading is not supported so, we need to pull the archive from nextcloud and copy over our install;

mkdir /root/scratch
cd /root/scratch
wget https://download.nextcloud.com/server/releases/latest.tar.bz2
tar -xjvf latest.tar.bz2
rsync -avz /root/scratch/nextcloud/ /usr/local/www/nextcloud/

Now we need to fix some permission:

cd /usr/loca/www
chown www:www nextcloud
cd nextcloud
chown -R www:www .htaccess .user.ini 3rdparty/ apps AUTHORS config/ console.php COPYING core/ cron.php dist/ index.html index.php lib/ occ ocm-provider/ ocs* public.php remote.php resources/ robots.txt status.php themes/ updater/ version.php

Now start redis and mysql and, restart fpm;

/usr/local/etc/rc.d/redis start
/usr/local/etc/rc.d/mysql-server start
/usr/local/etc/rc.d/php-fpm restart

All done, easy right? LOL.

OpenNMS / PagerDuty

With the release of OpenNMS 30, we found that the PagerDuty plugin was broken.

Issue #9 was opened on Jul 20 to address the error:

Error executing command: Unable to resolve root: missing requirement [root] osgi.identity; osgi.identity=opennms-plugins-pagerduty; type=karaf.feature; version="[0.1.3,0.1.3]"; filter:="(&(osgi.identity=opennms-plugins-pagerduty)(type=karaf.feature)(version>=0.1.3)(version<=0.1.3))" [caused by: Unable to resolve opennms-plugins-pagerduty/0.1.3: missing requirement [opennms-plugins-pagerduty/0.1.3] osgi.identity; osgi.identity=org.opennms.plugins.pagerduty-plugin; type=osgi.bundle; version="[0.1.3,0.1.3]"; resolution:=mandatory [caused by: Unable to resolve org.opennms.plugins.pagerduty-plugin/0.1.3: missing requirement [org.opennms.plugins.pagerduty-plugin/0.1.3] osgi.wiring.package; filter:="(&(osgi.wiring.package=org.opennms.integration.api.v1.alarms)(version>=0.5.0)(!(version>=1.0.0)))"]]

The devs did update the master tree a few weeks ago to accommodate the changes for OpenNMS 30, however it still does not build. I have forked the project and made one small change and it compiles and works.

Wiki.JS docker-compose w/ postgres persistent storage via NFS and Traefik

Here’s an example of our docker-file for Wiki.JS with NFS DB storage, Postgres and Traefik;

version: "3"
volumes:
  db-data:
      driver_opts:
        type: "nfs"
        o: addr=nfshost.example.com,nolock,soft,rw
        device: ":/mnt/Pool0/WikiJS"
services:
  db:
    image: postgres:11-alpine
    environment:
      POSTGRES_DB: wiki
      POSTGRES_PASSWORD: Supersecurepassword
      POSTGRES_USER: wikijs
    command: postgres -c listen_addresses='*'
    logging:
      driver: "none"
    restart: unless-stopped
    networks:
      - internal
    labels:
     - traefik.enable=false
    volumes:
      - type: volume
        source: db-data
        target: /var/lib/postgresql/data
        volume:
            nocopy: true


  wiki:
    image: ghcr.io/requarks/wiki:2
    depends_on:
      - db
    environment:
      DB_TYPE: postgres
      DB_HOST: db
      DB_PORT: 5432
      DB_USER: wikijs
      DB_PASS: Supersecurepassword
      DB_NAME: wiki
    restart: unless-stopped
    networks:
      - proxy
      - internal
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.ex-wikijs.entrypoints=https"
      - "traefik.http.routers.ex-wikijs.rule=Host(`wikijs.example.com`)"
      - "traefik.http.services.ex-wikijs.loadbalancer.server.port=3000"

networks:
  proxy:
    external: true
  internal:
    external: false

This stands up a postgres instance using the NFS mount as storage, allows the internal network to connect to it, stands up a wiki.js instance and gets it all going for you. All behind a Traefik proxy.

Rev.IO and Netbox…

Rev.IO has kind of a terrible asset management interface, (and they’ve killed their WWW subdomain without a redirect,… but that’s another rant) but we’ve chosen it due to its ability to handle MSP billing, so while it’s not ideal it’s something that my team has to work with.

So our first task was taking all of the Inventory that was in Rev.IO which as been transitioned into being our asset management platform as well since inventory is tracked in Rev.IO for billing purposes it does not make sense to use another platform given our small volume. The issue lies in how Rev.IO does its asset management and that is that you cannot tie an asset to a physical location. You can add multiple sites, but cannot associate an inventory item to a physical location. This is where Netbox comes in for us, since we have all of our physical locations in Netbox, we can associate an asset tag ID and asset ID from Rev.IO to a physical location or customer.

Here is what I did, with Python, to make this work;

First, we have to ensure that we import all of our customers from Rev.IO into Netbox, now we have two issues with Rev.IO here. Their documentation indicates that the ALL flag will get you all customer status’ – OPEN, CLOSED, PENDING etc… this is untrue, you must run each individually to get them all, the ALL flag, returns 0.

We created a custom_field in Netbox called revio that is the customer_id from Rev.io to allow pivoting on that id.

#!/usr/bin/python
import requests
import json
import argparse
import sys
import re

#Get customer list from Rev.IO and ensure they are all in Netbox
        r_parms = {"search.page_size":"100000","search.status":"OPEN"}
        response = requests.request("GET", url + "Customers", headers=headers, params=r_parms)
        netbox_r = requests.request("GET", netbox + "tenancy/tenants/?limit=10000", headers=netbox_h)
        #Read JSON in response
        data = response.json()
        #Read JSON in netbox
        netbox_d = netbox_r.json()
        #Iterate over JSON
        customercount = 0
        for i in data['records']:
                customercount += 1
                revio_id = i['customer_id']
                netbox_hasit = False
                for n in netbox_d['results']:
                        if n['custom_fields']['revio'] == revio_id:
                                netbox_hasit = True
                                break
                if not netbox_hasit:
                        print("No Netbox entry for " + i['service_address']['company_name'] + " - " + str(revio_id) + "Adding it")
			netbox_name = i['service_address']['company_name']
			netbox_slug = re.sub('[!@#$\'\".,&()]', '', netbox_name)
			netbox_slug = netbox_slug.replace("/", "-")
			netbox_p = {'name': netbox_slug, 'slug': netbox_slug.replace(" ", "-"), 'custom_fields': {'revio':revio_id}}
			sc = requests.post(netbox + "tenancy/tenants/", json=netbox_p, headers=netbox_h)
			print(sc.text)

The above will check Netbox for existing customers (tenants) that have the matching custom_field value and if not, add them. Again, you have to change the parms value from OPEN to CLOSED etc. to get everyone.

More to follow in a later post.