Runar Ovesen Hjerpbakk

Programmer. Software Architect. Technical Manager.

Simplify your crontab entries with crontab.guru

As you’ve seen from my previous posts, I’ve used cron a lot lately to schedule periodic tasks on my RaspberryPi. cron is driven by crontab, cron table files, configuration files that specifies shell commands to run periodically on a given schedule.

# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday; 
# │ │ │ │ │              7 is also Sunday on Raspbian)
# │ │ │ │ │
# │ │ │ │ │
# * * * * *  command to execute

The timing syntax is understandable enough. In addition to numbers, we can use special operators:

*	any value
,	value list separator
-	range of values
/	step values

An expression to achieve At 22:00 on every day-of-week from Monday through Friday looks like this:

0 22 * * 1-5

My problem is that I get the elements confused. Without reading the explanation, is 22 in the expression above minute or hour? You have to read the spec to find out.

Read More

The application to execute does not exist

I really do love dotnet-script and its almost perfect integration with Visual Studio Code. But as it is a .Net Core global tool, and VSCode uses file-based task specifications which know nothing of this, things can sometimes break.

I’ve create a simple script for giving me a nice text to share whenever I post a new post to this site. Sure, this can be further automated, but you’ve got to start someplace.

For development I use two different Macs, an iMac at home and a MacBook Pro during my commute. I started coding this on my iMac, but on my ride to work I got this error while trying to debug from VSCode on my MacBook Pro:

The application to execute does not exist: '/Users/sankra/.dotnet/tools/.store/dotnet-script/0.25.0/dotnet-script/0.25.0/tools/netcoreapp2.1/any/dotnet-script.dll'
The target process exited without raising a CoreCLR started event. Ensure that the target process is configured to use .NET Core. This may be expected if the target process did not run on .NET Core.
The program '[41202] dotnet' has exited with code 129 (0x81).

The script ran fine from the shell using dotnet script main.csx . So what is the cause of this error?

Read More

Automatically purge changed pages from the Cloudflare cache when adding a new post to Jekyll

This site is built with Jekyll, hosted on GitHub Pages, has DNS through Hover and is served by the Cloudflare CDN. The site is static, that is all pages are rendered ahead of time on the server. That means that even the simplest web server in the world could host hjerpbakk.com without issue. So why is Cloudflare a part of this stack?

I put it behind Cloudflare for three reasons:

  • Real simple TLS
  • Security, Cloudflare can protect you from DDoS attacks (not that this is an issue for me) and has a looong list of known bad players which are blocked from accessing your site.
  • Performance, Cloudflare has a global CDN and an excellent cache. Thus, your own server is hit far less than without this outer layer.

Since Cloudflare has a cache, how do you make sure the right parts of the cache are invalidated when you create new content? With a simple dotnet script that’s how!

Read More

Shrinking a Raspbian installation to save space

Yet another Pi post!

When I put Raspbian on the SD card used by my Raspberry Pi, I used the Raspbian Stretch with desktop version. That was perhaps a poor choice on my part, as I use the machine as a headless server. However, I’m not that skilled with Desktop Linux, so the mere fact that there were buttons to push during the installation and stuff actually worked, made me feel like a pro.

All those packages that I’ll never use, like LibreOffice, still take up precious space, so I wrote a simple script to remove some of them.

Read More

Automatically update and upgrade Raspbian

Continuing the theme of last night, today I improved the upgrade experience of my Raspberry Pi.

Manual upgrade

As per the documentation, update and upgrade are as easy as running these two commands. First update your system’s package list:

sudo apt -y update

Then upgrade all installed packages to their latest version:

sudo apt -y dist-upgrade

I use -y to answer yes to all prompts by default. Easy enough, but in our modern DevOpsy world, we need to automate this.

Read More

Automatically update OpenSSH on a Raspberry Pi

I just bought myself a gorgeous Raspberry Pi 3 Model B+ to use as a headless server and all-round tinkering machine. It’s small, power efficient and fast enough for my usage:

  • Cortex-A53 (ARMv8) 64-bit SoC @ 1.4GHz
  • 1GB LPDDR2 SDRAM

Enable SSH support

Installation is super easy, just follow the instructions on Raspberry Pi website, with one exception. As of the November 2016 release, the default Raspberry Pi OS, Raspbian, has the SSH server disabled by default.

To enable SSH, you need to either configure it after OS installation has completed as per instructions here, or while preparing your SD card:

For headless setup, SSH can be enabled by placing a file named ssh, without any extension, onto the boot partition of the SD card. When the Pi boots, it looks for the ssh file. If it is found, SSH is enabled, and the file is deleted. The content of the file does not matter: it could contain text, or nothing at all.

Read More

Remove stuck Launchpad progress bar from the Dock on macOS

I’m one of those guys who actually keeps the Launchpad icon in the dock on macOS. I have it there to see the progress of installations of apps and updates from the App Store.

And it seems that not many people does this, for every so often the progress bar hangs. That is, it is there, empty, never going away. I’ve reported this to Apple through their Bug Reporter, but the problem has persisted through many versions of macOS.

Read More

Error RZ3007 - Targeted tag name cannot be null or whitespace.

The first release candidate of ASP.NET Core 2.1 is out with a lot of performance improvements and  new features. 

One of the features is Razor compilation on build, enabling catching more errors at design time and improved startup time. This however broke one of my apps.

After updating the app to 2.1, navigating to a Razor view met me with the following error:

Microsoft.AspNetCore.Mvc.Razor.Compilation.CompilationFailedException: One or more compilation failures occurred:
(0,0): Error RZ3007: Targeted tag name cannot be null or whitespace.
   at Microsoft.AspNetCore.Mvc.Razor.Internal.RazorViewCompiler.CompileAndEmit(String relativePath)
   at Microsoft.AspNetCore.Mvc.Razor.Internal.RazorViewCompiler.OnCacheMiss(String normalizedPath)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Razor.Internal.DefaultRazorPageFactoryProvider.CreateFactory(String relativePath)
   at Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.CreateCacheResult(HashSet`1 expirationTokens, String relativePath, Boolean isMainPage)
   at Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.OnCacheMiss(ViewLocationExpanderContext expanderContext, ViewLocationCacheKey cacheKey)
   at Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.LocatePageFromViewLocations(ActionContext actionContext, String pageName, Boolean isMainPage)
   at Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.FindView(ActionContext context, String viewName, Boolean isMainPage)
   at Microsoft.AspNetCore.Mvc.ViewEngines.CompositeViewEngine.FindView(ActionContext context, String viewName, Boolean isMainPage)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.FindView(ActionContext actionContext, ViewResult viewResult)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
   at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at MediaServer.Startup.<>c__DisplayClass5_0.<<Configure>b__0>d.MoveNext() in /Users/sankra/projects/MediaServer/MediaServer/Startup.cs:line 104
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware:Error: An unhandled exception has occurred while executing the request.

Read More

Jekyll error - bad Request-Line

I use the excellent Jekyll to create this and a couple of other websites. Jekyll is a static website generator written in Ruby and plays very nicely with GitHub Pages.

But since it’s software, after all, it too needs updating once in a while. And as you know dear readers, all software sucks.

So I updated jekyll and other needed gems and tried to serve the page locally:

$ bundle exec jekyll serve --drafts --watch --baseurl '' --config _config.yml,_config-dev.yml --limit_posts 10
Configuration file: _config.yml
Configuration file: _config-dev.yml
            Source: /Users/hjerpbakk/projects/hjerpbakk.github.io
       Destination: /Users/hjerpbakk/projects/hjerpbakk.github.io/_site
 Incremental build: disabled. Enable with --incremental
      Generating... 
                    done in 12.903 seconds.
 Auto-regeneration: enabled for '/Users/hjerpbakk/projects/hjerpbakk.github.io'
    Server address: http://127.0.0.1:4000/
  Server running... press ctrl-c to stop.
[2018-03-20 16:40:31] ERROR bad Request-Line `\x16\x03\x01\x00?\x01\x00\x00?\x03\x03?t&,?\x1E??\x1AJmc?_?U??c\x00<'.
[2018-03-20 16:40:31] ERROR bad Request-Line `\x16\x03\x01\x00?\x01\x00\x00?\x03\x03aS?PP???c?\x1Ab~?K'\x13\b\x00w????M?8?\x7FK/\x00\x00.?,?+?$?#?'.
[2018-03-20 16:40:31] ERROR bad URI `?'.
[2018-03-20 16:40:31] ERROR bad Request-Line `\x16\x03\x01\x00?\x01\x00\x00?\x03\x03?~F?Еs''?ʓ???\x16??e?#\b?\x05a+?{\x18ܬ\x00\x00(?,?+?$?#?'.
[2018-03-20 16:40:31] ERROR bad Request-Line `\x16\x03\x01\x00?\x01\x00\x00?\x03\x03 ?<\x18J3z??{?\x03?KĘ*?\r??`"+y"L?F??P\x00\x00.?,?+?$?#?'.
[2018-03-20 16:40:31] ERROR bad URI `?'

Bad request lines as far as the eye can see.

Read More

.dockerignore is your friend

While working on a particular project built with a multi-stage Dockerfile I got this error:

Step 13/19 : RUN dotnet test "./DashboardServerTests/DashboardServerTests.csproj" -c Release --no-restore
 ---> Running in ac850e55464c
Build started, please wait...
/usr/share/dotnet/sdk/2.0.3/Sdks/Microsoft.NET.Sdk/build/Microsoft.PackageDependencyResolution.targets(323,5): error : Assets file '/Users/sankra/projects/DashboardServer/Grafana/obj/project.assets.json' not found. Run a NuGet package restore to generate this file. [/source/Grafana/Grafana.csproj]

Read More