Skip to content

My Blog

Just tech stuff. :)

vCenter Update doesn't work anymore

You are trying to update your vCenter, but suddenly you get a network error? Same.... And spoiler: it was not the network.

Basically Broadcom wen’t “fuck everyone” and started to move everything over to their side. Even the vCenter repositories. Even better, they added a download token too...

But no, they don’t change the vCenter to refelect those changes, I mean, that would be too obvious.

What now?

The Fix

Get your download token: https://knowledge.broadcom.com/external/article/390121?

I won’t summarize here, because they like to change everything about twice a day.

Now change the URL in your update settings in vami to this:

https://dl.broadcom.com/<download-token>/PROD/COMP/VCENTER/vmw/8d167796-34d5-4899-be0a-6daade4005a3/<target-version>

Yes, including the very specific verion. Why have an auto check, if you have to set the version manually anyway. :) So for 8.0.3 its like this:

https://dl.broadcom.com/<download-token>/PROD/COMP/VCENTER/vmw/8d167796-34d5-4899-be0a-6daade4005a3/8.0.3.00800

And also change the ESXi URLs if needed:

https://dl.broadcom.com/<Download Token>/PROD/COMP/ESX_HOST/main/vmw-depot-index.xml
https://dl.broadcom.com/<Download Token>/PROD/COMP/ESX_HOST/addon-main/vmw-depot-index.xml
https://dl.broadcom.com/<Download Token>/PROD/COMP/ESX_HOST/iovp-main/vmw-depot-index.xml
https://dl.broadcom.com/<Download Token>/PROD/COMP/ESX_HOST/vmtools-main/vmw-depot-index.xml

move-docker-root

Moving a docker root is not hard, but comes with 1 or 2 gotchas. In my case, I wanted to attach a disk to the docker root placed in /srv/docker, so I had to move the data out of the way, mount the disk, and than move it back.

Gotchas: - Just running systemctl stop docker won’t actually stop docker - File permissions for overlay2 is VERY important (you will run into permission denied on /tmp or similar) - Finding the right commands :)

How To:

# Getting Docker to shut up
systemctl disable --now docker.socket
systemctl disable --now docker.service

# Getting the data out of the way
mv /srv/docker /root/docker

# Now do what you must
# if need be, stop it again and rm -rf /srv/docker/*

# Lets get the data back
cp -R -a /root/docker/* /srv/docker/

# Start docker and check that all is good
systemctl enable --now docker.service
systemctl enable --now docker.socket

# Now the fun part, somehow overlay2 sometimes mounts the folder from your moved files. fun right? just umount those
umount /root/docker/overlay2/*/merged

# If so, cleanup after yourself
rm -rf /root/docker

Fix USB Modem

We have a USB stick with a SIM in it, for sending SMS. When pluging in the new stick, it always was showing up as a CD ROM instead of a usb-serial. This is what we did to solve it:

dnf install -y usbutils usb_modeswitch python3-pip git

# Setup USB Modem
lsusb
# > Bus 001 Device 004: ID 3566:2001 Mobile Mobile

echo "#!/bin/bash

# Fix USB Mode
/usr/sbin/usb_modeswitch -v 0x3566 -p 0x2001 -X

# Wait 3 seconds than read that stick for usb serials
sleep 3
echo '3566 2001 ff' | sudo tee /sys/bus/usb-serial/drivers/option1/new_id" > /usr/local/sbin/fix-huawei-stick.sh
chmod +x /usr/local/sbin/fix-huawei-stick.sh

echo 'ATTRS{idVendor}=="3566", ATTRS{idProduct}=="2001", RUN+="/usr/local/sbin/fix-huawei-stick.sh"' > /etc/udev/rules.d/99-huawei.rules

udevadm control --reload-rules
udevadm trigger


echo "usbserial
option" > /etc/modules-load.d/sms.conf


reboot

silverbullet-decimal-index

I like the Johnny.Decimal System, so I try to use it in Silverbullet. To make navigation easier, I’ve created a widget, that shows me all matching notes under the current one.

-- priority: 30
event.listen {
  name = "hooks:renderBottomWidgets",
  run = function(e)
    local currentPage = editor.getCurrentPage():match("[^/]+$")

    -- check last path segment, that it is decimal system
    local isMatch = currentPage:match("^[A-Z] .*$") or currentPage:match("^[A-Z][0-9][0-9] .*$") or currentPage:match("^[0-9][0-9] .*$") or currentPage:match("^[0-9][0-9]\\.[0-9][0-9] .*$")

    if isMatch then

      local subPages = query[[
        from p = index.tag "page"
        where p.name:match("^"..editor.getCurrentPage().."/[^/]+$")
        select {
          Index = "[[" .. p.name .. "]]",
        }
      ]]
      print("index subpages", #subPages)
      if #subPages > 0 then
        return widget.new {markdown = "![[meta/templates/decimal-index]]"}
      end
    end

    return nil

  end
}

silverbullet-files-handling

I love my Silverbullet notes instance. But the file handling was not perfect for me. So I created a small setup, that will help me with handling the files, and mapping them to pages:

Uploads

I’ve created a upload button in my action bar, that handles where to put the file. It just keeps the original file name. But this in your config:

config.set {
  actionButtons = {
    {
      icon = "upload",
      run = function()
        local file = editor.uploadFile("", nil)
        local newFileName = editor.getCurrentPage().."_files/".. file.name
        space.writeDocument(newFileName, file.content)
        editor.insertAtCursor("[["..newFileName.."]]")
      end,
      description = "Add a new attachement"
    }
 }
}

Showing the Files

To see which files belong to a site, I have this widget added under meta/files-widget, but you can put it where ever you like:

-- priority: 20
event.listen {
  name = "hooks:renderBottomWidgets",
  run = function(e)
    -- Get Files
    local files = space.listFiles()

    -- Loop
    local hasFiles = false
    local filesOut = "| File | Size | Changed |\n"
    filesOut = filesOut .. "|---|---|---|\n"
    for _, file in ipairs(files) do
        -- If lies under the current page
        if(starts_with(file.name, editor.getCurrentPage().. "_files/")) then
          -- not .md files
          if(not ends_with(file.name, ".md")) then

            filesOut = filesOut .. "|[["..file.name.."]]"
            filesOut = filesOut .. "|" .. human_readable_bytes(file.size)
            filesOut = filesOut .."|"..os.date("%Y-%m-%d %H:%M:%S", file.lastModified / 1000)
            filesOut = filesOut .."|\n"
            hasFiles = true
          end
        end
    end
    if hasFiles then
      return widget.new {markdown = filesOut}
    else
      return nil
    end
  end
}

Silverbullet to GitHub

This website is hosted on GitHub Pages, and the content is directly synced from my Silverbullet instance, to GitHub. I’ve set it up this way:

Setup

To set this up, you’ll have to create a ssh key-pair, and put it into your space somewhere. I’ve put it into a folder Z Public/.keys inside my instance. Then add that public key to your GitHub account, or to your repository, so it can be used to sync the content.

I also added a Z Public/.gitignore to exclude the key, like this:

.keys/*

Then set this folder up as a new git repo, and add the origin to it.

Now you need to create a github workflow and a config to make it work with mkdocs. Both can be found in the GitHub Repo.

Sync Command

After that, create a new page in your Silverbullet (for me it lives in meta/command-git-sync-github) and put this script in it:

command.define{
  name = "Public-Site: Sync",
  run = function()

    local function gitRun(args)
      local ok = shell.run("bash", {"-c" ,args .. " >> /tmp/git-log 2>&1"})
      return ok
    end

    gitRun("GIT_SSH_COMMAND=\"ssh -i '/space/Z Public/.keys/id_rsa' -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git -C '/space/Z Public' pull --no-commit --rebase origin master")

    local ok1 = gitRun("git -C '/space/Z Public' add . --all")
    local ok2 = gitRun("git -C '/space/Z Public' commit -m auto")
    local ok3 = gitRun("GIT_SSH_COMMAND=\"ssh -i '/space/Z Public/.keys/id_rsa' -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git -C '/space/Z Public' push origin master")

    if ok1 and ok2 and ok3 then
      editor.flashNotification("synced")
    else
      editor.flashNotification("sync did not work")
    end
  end
}

mysqldump is locking the db

If your mysqldump command is locking the DB and you can’t edit the command (because another application is starting it), just add this to your /etc/my.cnf:

[mysqldump]
single-transaction
quick
skip-lock-tables

Set ESXi Syslog Hosts with Script

Here's the script:

$CONFIG = @{
    "logServer" = "graylog.domain.local";
    "logPort" = 1514;
    "logProto" = "tcp";
    "vcenter" = "vcsa.domain.local";
    "cluster" = "Cluster1";
}

# Startup
Import-Module VCF.PowerCLI
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false | Out-Null
$syslogURL = "$($CONFIG["logProto"])://$($CONFIG["logServer"]):$($CONFIG["logPort"])"

# Connect
Connect-VIServer -Server $CONFIG["vcenter"]

# Loop through hosts
$vmHosts = Get-Cluster -Name $CONFIG["cluster"] | Get-VMHost 
foreach($vmHost in $vmHosts) {
    Write-Host "Configuring $($vmHost.Name)"

    # Set syslog
    $advancedSetting = Get-AdvancedSetting -Entity $vmHost -Name "Syslog.global.logHost"
    $advancedSetting | Set-AdvancedSetting -Value $syslogURL -Confirm:$false -ErrorAction Stop | Out-null

    # Activate Firewall rule
    $rule = Get-VMHostFirewallException -VMHost $vmHost | ? {$_.Name -eq "syslog"}
    if($rule) {
        $rule | Set-VMHostFirewallException -Enabled:$true -ErrorAction Stop | Out-Null
    } else {
        Write-Host "ERROR - Rule not found"
        exit
    }

    # Reload syslog service
    $esxcli = Get-EsxCli -VMHost $vmHost
    $esxcli.system.syslog.reload.Invoke() | out-null
}

Disconnect-VIServer -Server $CONFIG["vcenter"] -Confirm:$false

Yourls – Generate Password

php -r "echo 'phppass:'. password_hash('yourpassword', PASSWORD_BCRYPT) . PHP_EOL;"

GeoIP in Nginx Proxy Manager

I’ve tried to add GeoIP2 to my Nginx Proxy Manager. After finding a few blogs and articles that “explain” how to do it, I got more confused. Here is the final guide, that will help you.

First you need to setup a 2nd docker container, that will download your GeoIP2 database from maxmind. They got a docker image for that. Should be simple.

After that, add the databases to your nginx proxymanager like this:

(...)
services:
  npm:
    (...)
    volumes:
      (...)
      - /your/geoip/folder:/geoip

Now add files to the nginx proxy manager data volume.

Add/create the file nginx/custom/http_top.conf to your npm data folder:

geoip2 /geoip/GeoLite2-Country.mmdb {
    $geoip2_data_country_iso_code country iso_code;
}


map $geoip2_data_country_iso_code $allowed_country {
  default 0;
  CH 1;
  # Add your countries like CH here
}

Add/create the file nginx/custom/root_top.conf to your npm data folder:

load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;
load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so;

Now add this to all your proxies (or the ones you want it to work for) in the advanced tab:

if ($allowed_country = 0) {
    return 404;
}

IT WORKS NOW!