post

How to watch for releases of upstream projects

Do you want to know when a new version of your favorite project is released? Do you want to make your job as packager easier? If so, this article is for you. It introduces you to the world of release-monitoring.org. You’ll see how it can help you catch up with upstream releases.

What is release-monitoring.org?

The release-monitoring.org is a combination of two applications: Anitya and the-new-hotness.

Anitya is what you can see when visiting release-monitoring.org. You can use it to add and manage your projects. Anitya also checks for new releases periodically.

The-new-hotness is an application that catches the messages emitted by Anitya. It creates a Bugzilla issue if the project is mapped to a Fedora package.

How to use release-monitoring.org

Now that you know how it works, let’s focus on how you can use it.

Index page of release-monitoring.org

First think you need to do is to log in. Anitya provides a few options you can use to log in, including the Fedora Account System (FAS), Yahoo!, or a custom OpenID server.

Login page

When you’re logged in, you’ll see new options in the top panel.

Anitya top panel

Add a new project

Now you can add a new project. It’s always good to check whether the project is already added.

Add project form

Next, fill in the information about the project:

  • Project name – Use the upstream project name
  • Homepage – Homepage of the project
  • Backend – Backend is simply the web hosting where the project is hosted. Anitya offers many backends you can chose from. If you can’t find a backend for your project, you can use the custom backend. Every backend has its own additional fields. For example, BitBucket has you specify owner/project.
  • Version scheme – This is used to sort received versions. Right now, Anitya only supports RPM version scheme.
  • Version prefix – This is the prefix that is stripped from any received version. For example, if the tag on GitHub is version_1.2.3, you would use version_ as version prefix. The version will then be presented as 1.2.3. The version prefix v is stripped automatically.
  • Check latest release on submit – If you check this, Anitya will do an initial check on the project when submitted.
  • Distro – The distribution in which this project is used. This could be also added later.
  • Package – The project’s packaged name in the distribution. This is required when the Distro field is filled in.

When you’re happy with the project, submit it. Below you can see how your project may look after you submit.

Project page

Add a new distribution mapping

If you want to map the project to a package on a specific distribution, open up the project page first and then click on Add new distribution mapping.

Add distribution mapping form

Here you can chose any distribution already available in Anitya, fill in the package name, and submit it. The new mapping will show up on the project page.

Automatic filing of Bugzilla issues

Now you created a new project and created a mapping for it. This is nice, but how does this help you as a packager? This is where the-new-hotness comes into play.

Every time the-new-hotness sees a new update or new mapping message emitted by Anitya, it checks whether this project is mapped to a package in Fedora. For this to work, the project must have a mapping to Fedora added in Anitya.

If the package is known, the-new-hotness checks the notification setting for this package. That setting can be changed here. The last check the-new-hotness does is whether the version reported by Anitya is newer than the current version of this package in Fedora Rawhide.

If all those checks are positive, the new Bugzilla issue is filed and a Koji scratch build started. After the Koji build is finished, the Bugzilla is updated with output.

Future plans for release-monitoring.org

The release-monitoring.org system is pretty amazing, isn’t it? But this isn’t all. There are plenty of things planned for both Anitya and the-new-hotness. Here’s a short list of future plans:

Anitya

  • Add libraries.io consumer – automatically check for new releases on libraries.io, create projects in Anitya and emit messages about updates
  • Use Fedora package database to automatically guess the package name in Fedora based on the project name and backend
  • Add semantic and calendar version scheme
  • Change current cron job to service: Anitya checks for new versions periodically using a cron job. The plan is to change this to a service that checks projects using queues.
  • Support for more than one version prefix

the-new-hotness

  • File Github issues for Flathub projects when a new version comes out
  • Create pull requests in Pagure instead of filing a Bugzilla issue
  • Move to OpenShift – this should make deployment much easier than how it is now
  • Convert to Python 3 (mostly done)

Both

  • Conversion to fedora-messaging – This is already in progress and should make communication between Anitya and the-new-hotness more reliable.

Photo by Alexandre Debiève on Unsplash.

post

Python 3.8 alpha in Fedora

The Python developers have released the first alpha of Python 3.8.0 and you can already try it out in Fedora! Test your Python code with 3.8 early to avoid surprises once the final 3.8.0 is out in October.

Install Python 3.8 on Fedora

If you have Fedora 29 or newer, you can install Python 3.8 from the official software repository with dnf:

$ sudo dnf install python38

As more alphas, betas and release candidates of Python 3.8 will be released, the Fedora package will receive updates. No need to compile your own development version of Python, just install it and have it up to date. New features will be added until the first beta.

Test your projects with Python 3.8

Run the python3.8 command to use Python 3.8 or create virtual environments with the builtin venv module, tox or with pipenv. For example:

$ git clone https://github.com/benjaminp/six.git
Cloning into 'six'...
$ cd six/
$ tox -e py38
py38 runtests: commands[0] | python -m pytest -rfsxX
================== test session starts ===================
platform linux -- Python 3.8.0a1, pytest-4.2.1, py-1.7.0, pluggy-0.8.1
collected 195 items

test_six.py ...................................... [ 19%]
.................................................. [ 45%]
.................................................. [ 70%]
..............................................s... [ 96%]
....... [100%]
========= 194 passed, 1 skipped in 0.25 seconds ==========
________________________ summary _________________________
py38: commands succeeded
congratulations 🙂

What’s new in Python 3.8

So far, only the first alpha was released, so more features will come. You can however already try out the new walrus operator:

$ python3.8
Python 3.8.0a1 (default, Feb 7 2019, 08:07:33)
[GCC 8.2.1 20181215 (Red Hat 8.2.1-6)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> while not (answer := input('Say something: ')):
... print("I don't like empty answers, try again...")
...
Say something:
I don't like empty answers, try again...
Say something: Fedora
>>>

And stay tuned for Python 3.8 as python3 in Fedora 31!

post

Convert your Fedora Silverblue to HTPC with Kodi

Ever wanted to create a HTPC from old computer laying around. Or just have some spare time and want to try something new. This article could be just for you. It will show you the step by step process to convert a Fedora Silverblue to a fully fledged HTPC.

What is Fedora Silverblue, Kodi and HTPC?

Fedora Silverblue is a system similar to Fedora Workstation. It offers an immutable filesystem (only /var and /etc are writable) and atomic updates using an ostree image, which offers reliable updates with ability to rollback to previous version easily. If you want to find out more about Fedora Silverblue visit https://silverblue.fedoraproject.org/ or if you want to try it by yourself you can get it here.

Kodi is one of the best multimedia player available. It provides plenty of features (like automatic downloads of metadata for movies, support for UPnP etc.) and it’s open source. It also has many addons. So if you are missing any functionality you could probably find an addon for it.

HTPC is just an acronym for Home Theater PC in simple words a PC that is mainly used as an entertainment station. You can connect it to TV or any monitor and just use it to watch your favorite movies, TV shows or listen to your favorite music.

Why choosing Silverblue to create an HTPC?

So why choosing Fedora Silverblue for HTPC? The main reasons are:

  • Reliability – you don’t need to fear that after update everything stop working and if it does, I can rollback easily
  • New technology – it is a good opportunity to play with a new technology.

And why to choose Kodi ? As stayted before it’s one of the best multimedia player and it’s packaged as a flatpak, which make it easy to install on Silverblue.

Conversion of Fedora Silverblue to HTPC

Let’s go step by step through this process and see how to create a fully usable HTPC from Fedora Silverblue.

1. Installation of Fedora Silverblue

First thing you need to do is to install Fedora Silverblue, this guide will not cover the installation process, but you can expect similar process as with standard Fedora Workstation installation. You can get the Fedora Silverblue ISO here

Create only the root user during the installation with some password. We will create a user for Kodi later without password.

2. Booting to terminal

This part will be a little tricky. You need to bypass GNOME and end the boot sequence in terminal. Otherwise you will end up in GNOME initial setup process, which will not allow you to create user without password.

To bypass the GNOME you need to press the ‘e’ key in GRUB menu to edit the GRUB entry. When editing the GRUB entry just look for the line starting with linux16 and add 3 to end of this line. Then continue the boot sequence with CTRL + x. Don’t worry about the changes, they are used only for this session.

GRUB menu
GRUB entry edited

You will end up in terminal where you need to login as root.

3. Creation of user for Kodi

When you are in the terminal logged as root, you need to create a user that will be used by Kodi. This can be done using the useradd command.

useradd kodi

4. Installation of Kodi from Flathub

To install the Kodi in flatpak you first need to add a Flathub remote repository.

flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo

With the Flathub repository added the installation of Kodi is simple.

flatpak install flathub tv.kodi.Kodi

5. Set Kodi as autostart application

First we need to create the autostart directory for the kodi user, this is easier if you switch to kodi user directly.

su kodi
mkdir -p /home/kodi/.config/autostart

Then you need to create a symlink for the Kodi desktop file.

ln -s /var/lib/flatpak/exports/share/applications/tv.kodi.Kodi.desktop /home/kodi/.config/autostart/tv.kodi.Kodi.desktop

The last thing that will prevent for autostart to work correctly is the GNOME initial setup. To disable it just create a gnome-initial-setup-done file in .config directory of kodi user.

echo "yes" > /home/kodi/.config/gnome-initial-setup-done

You can now switch back to root for the next steps.

exit

6. Set autologin for kodi user

This step is very useful together with autostart of Kodi. Every time you restart your HTPC you will end up directly in Kodi and not in the GDM or GNOME shell. To set the auto login you need to add the following lines to /etc/gdm/custom.conf to the [daemon] section

AutomaticLoginEnable=True 
AutomaticLogin=kodi

7. Enable automatic updates

For HTPC automatic updates you will need a cron job. But because cron is not part of the standard Fedora Silverblue installation you need to install it first. In this step I also recommend to do upgrade of the Fedora Silverblue first before layering the cron package.

rpm-ostree upgrade

rpm-ostree install cronie

After this you need to reboot your computer, to apply the new updates.

reboot

To be able to setup cron in this phase you need to do the second step again and log in as root. After this you need to edit the crontab.

crontab -e

And add the following line to it.

0 4 * * 3 flatpak update -y; rpm-ostree upgrade; reboot

This will create a new cron job, which will update any flatpaks (Kodi in this case), update Silverblue and does a restart to apply the changes.

This job will run at 4 AM on Wednesday. It is recommended to set this to a time when nobody will use the HTPC.

Restart the computer now.

reboot

8. Disable GNOME features

There are few GNOME features that could be annoying when using Fedora Silverblue as HTPC. Most of these features could be setup directly in Kodi anyway, so if you want them later it’s easy to set them directly in Kodi.

To do this exit Kodi and open the terminal. Press Super key (this is the key between ALT and CTRL) and type terminal. Once the terminal will be open and you need to type the following commands.

# Display dim
dconf write "/org/gnome/settings-daemon/plugins/power/idle-dim" false

# Sleep over time/
dconf write "/org/gnome/settings-daemon/plugins/power/sleep-inactive-ac-type" 0

# Screensaver
dconf write "/org/gnome/desktop/screensaver/lock-enabled" false

# Automatic updates through gnome-software
dconf write "/org/gnome/software/download-updates" false

And that’s it, you just need to do one last restart to apply the dconf changes. After the restart you will end up directly in Kodi.

Kodi

What now?

Now I will recommend you to play with the Kodi settings a little bit and set it up to your liking. You can find plenty of guides on the internet.

If you want to automate the process you can use my ansible script that was written just for this occasion.


Photo by Sven Scheuermeier on Unsplash

post

Fedora logo redesign

The current Fedora Logo has been used by Fedora and the Fedora Community since 2005. However, over the past few months, Máirín Duffy and the Fedora Design team, along with the wider Fedora community have been working on redesigning the Fedora logo.

Far from being just an arbitrary logo change, this process is being undertaken to solve a number of issues encountered with the current logo. Some of the issues with the current logo include the lack of a single colour variant, and, consequently the logo not working well on dark backgrounds. Other challenges with the current logo is confusion with other well-known brands, and the use of a proprietary font.

The new Fedora Logo design process

Last month, Máirín posted an amazing article about the history of the Fedora logo, a detailed analysis of the challenges with the current logo, and a proposal of two candidates. A wide ranging discussion with the Fedora community followed, including input from Matt Muñoz, the designer of the current Fedora logo. After the discussions, the following candidate was chosen for further iteration:

In a follow-up post this week, Máirín summarizes the discussions and critiques that took place around the initial proposal, and details the iterations that took place as a result.

After all the discussions and iterations, the following 3 candidates are where the team is currently at:

Join the discussion on the redesign over at Máirín’s blog, and be sure to read the initial post to get the full story on the process undertaken to get to this point.

post

4 cool new projects to try in COPR for February 2019

COPR is a collection of personal repositories for software that isn’t carried in Fedora. Some software doesn’t conform to standards that allow easy packaging. Or it may not meet other Fedora standards, despite being free and open source. COPR can offer these projects outside the Fedora set of packages. Software in COPR isn’t supported by Fedora infrastructure or signed by the project. However, it can be a neat way to try new or experimental software.

Here’s a set of new and interesting projects in COPR.

CryFS

CryFS is a cryptographic filesystem. It is designed for use with cloud storage, mainly Dropbox, although it works with other storage providers as well. CryFS encrypts not only the files in the filesystem, but also metadata, file sizes and directory structure.

Installation instructions

The repo currently provides CryFS for Fedora 28 and 29, and for EPEL 7. To install CryFS, use these commands:

sudo dnf copr enable fcsm/cryfs
sudo dnf install cryfs

Cheat

Cheat is a utility for viewing various cheatsheets in command-line, aiming to help remind usage of programs that are used only occasionally. For many Linux utilities, cheat provides cheatsheets containing condensed information from man pages, focusing mainly on the most used examples. In addition to the built-in cheatsheets, cheat allows you to edit the existing ones or creating new ones from scratch.

Installation instructions

The repo currently provides cheat for Fedora 28, 29 and Rawhide, and for EPEL 7. To install cheat, use these commands:

sudo dnf copr enable tkorbar/cheat
sudo dnf install cheat

Setconf

Setconf is a simple program for making changes in configuration files, serving as an alternative for sed. The only thing setconf does is that it finds the key in the specified file and changes its value. Setconf provides only a few options to change its behavior — for example, uncommenting the line that is being changed.

Installation instructions

The repo currently provides setconf for Fedora 27, 28 and 29. To install setconf, use these commands:

sudo dnf copr enable jamacku/setconf
sudo dnf install setconf

Reddit Terminal Viewer

Reddit Terminal Viewer, or rtv, is an interface for browsing Reddit from terminal. It provides the basic functionality of Reddit, so you can log in to your account, view subreddits, comment, upvote and discover new topics. Rtv currently doesn’t, however, support Reddit tags.

Installation instructions

The repo currently provides Reddit Terminal Viewer for Fedora 29 and Rawhide. To install Reddit Terminal Viewer, use these commands:

sudo dnf copr enable tc01/rtv
sudo dnf install rtv
post

Fedora Classrooms: Silverblue and Badge Design

Fedora Classroom sessions continue with two introductory sessions, on using Fedora Silverblue (February 7), and creating Fedora badges designs (February 10). The general schedule for sessions is availble on the wiki, along with resources and recordings from previous sessions. Details on both these upcoming sessions follow.

Topic: Fedora Silverblue

Fedora Silverblue is a variant of Fedora Workstation that is composed and delivered using ostree technology. It uses some of the same RPMs found in Fedora Workstation but delivers them in a way that produces an “immutable host” for the end user.  This provides atomic upgrades for end users and allows users to move to a fully containerized environment using traditional containers and flatpaks.

This session is aimed at users who want to learn more about Fedora Silverblue,
ostree, rpm-ostree, containers, and Flatpaks.  It is expected that attendees have some basic Linux knowledge.

The following topics will be covered:

  • What’s an immutable host?
  • How is Fedora Silverblue different from Fedora Workstation?
  • What is ostree and rpm-ostree?
  • Upgrading, rollbacks, and rebasing your host.
  • Package layering with rpm-ostree.
  • Using containers and container tools (podman, buildah).
  • Using Flatpaks for GUI applications

When and where

Instructor

Micah Abbott is a Principal Quality Engineer working for Red Hat. He remembers his first introduction to Linux was during university when someone showed him Red Hat Linux running on a DEC Alpha Workstation.  He’s dabbled with  various distributions in the following years, but has always had a soft spot for  Fedora. Micah has recently been contributing towards the development  of  Fedora/Red Hat CoreOS and before that Project Atomic.  He enjoys engaging with the community to help solve problems that users are facing and has most recently been spending a lot of time involved with the Fedora Silverblue community.

Topic: Creating Fedora Badges Designs

Fedora Badges is a gamification system created around the hard work of the Fedora community on the various aspects of the Fedora Project. The Badges project helps to drive and motivate Fedora contributors to participate in all different parts of Fedora development, quality, content, events, and stay active in community initiatives. This classroom will explain the process of creating a design for a Fedora Badge.

Here is the agenda for the classroom session:

  • What makes a Fedora Badge?
  • Overview of resources, website, and tickets.
  • Step by step tutorial to design a badge.

Resources needed:

  • Inkscape.
  • Comfortaa typeface.
  • Fedora badges resources (colour palettes, graphics, templates).

On Fedora, inkscape and comfortaa can be installed using dnf:

sudo dnf install inkscape aajohan-comfortaa-fonts

When and where

Instructor

Marie Nordin is a graphic designer and fine artist, with a day job as a Assistant Purchasing Manager in Rochester, NY. Marie began working on the Fedora Badges project and the Fedora Design Team in 2013 through an internship with the Outreachy program. She has maintained the design side of the Fedora Badges project for four years, as well as running workshops and teaching others how to  contribute designs to Badges.

post

3 simple and useful GNOME Shell extensions

The default desktop of Fedora Workstation — GNOME Shell — is known and loved by many users for its minimal, clutter-free user interface. It is also known for the ability to add to the stock interface using extensions. In this article, we cover 3 simple, and useful extensions for GNOME Shell. These three extensions provide a simple extra behaviour to your desktop; simple tasks that you might do every day.

Installing Extensions

The quickest and easiest way to install GNOME Shell extensions is with the Software Application. Check out the previous post here on the Magazine for more details:

Removable Drive Menu

Removable Drive Menu extension on Fedora 29

First up is the Removable Drive Menu extension. It is a simple tool that adds a small widget in the system tray if you have a removable drive inserted into your computer. This allows you easy access to open Files for your removable drive, or quickly and easily eject the drive for safe removal of the device.

Removable Drive Menu in the Software application

Extensions Extension.

The Extensions extension is super useful if you are always installing and trying out new extensions. It provides a list of all the installed extensions, allowing you to enable or disable them. Additionally, if an extension has settings, it allows quick access to the settings dialog for each one.

the Extensions extension in the Software application

Frippery Move Clock

Finally, there is the simplest extension in the list. Frippery Move Clock, simply moves the position of the clock from the center of the top bar to the right, next to the status area.

post

Mind map yourself using FreeMind and Fedora

A mind map of yourself sounds a little far-fetched at first. Is this process about neural pathways? Or telepathic communication? Not at all. Instead, a mind map of yourself is a way to describe yourself to others visually. It also shows connections among the characteristics you use to describe yourself. It’s a useful way to share information with others in a clever but also controllable way. You can use any mind map application for this purpose. This article shows you how to get started using FreeMind, available in Fedora.

Get the application

The FreeMind application has been around a while. While the UI is a bit dated and could use a refresh, it’s a powerful app that offers many options for building mind maps. And of course it’s 100% open source. There are other mind mapping apps available for Fedora and Linux users, as well. Check out this previous article that covers several mind map options.

Install FreeMind from the Fedora repositories using the Software app if you’re running Fedora Workstation. Or use this sudo command in a terminal:

$ sudo dnf install freemind

You can launch the app from the GNOME Shell Overview in Fedora Workstation. Or use the application start service your desktop environment provides. FreeMind shows you a new, blank map by default:

FreeMind initial (blank) mind map

A map consists of linked items or descriptions — nodes. When you think of something related to a node you want to capture, simply create a new node connected to it.

Mapping yourself

Click in the initial node. Replace it with your name by editing the text and hitting Enter. You’ve just started your mind map.

What would you think of if you had to fully describe yourself to someone? There are probably many things to cover. How do you spend your time? What do you enjoy? What do you dislike? What do you value? Do you have a family? All of this can be captured in nodes.

To add a node connection, select the existing node, and hit Insert, or use the “light bulb” icon for a new child node. To add another node at the same level as the new child, use Enter.

Don’t worry if you make a mistake. You can use the Delete key to remove an unwanted node. There’s no rules about content. Short nodes are best, though. They allow your mind to move quickly when creating the map. Concise nodes also let viewers scan and understand the map easily later.

This example uses nodes to explore each of these major categories:

Personal mind map, first level

You could do another round of iteration for each of these areas. Let your mind freely connect ideas to generate the map. Don’t worry about “getting it right.” It’s better to get everything out of your head and onto the display. Here’s what a next-level map might look like.

Personal mind map, second level

You could expand on any of these nodes in the same way. Notice how much information you can quickly understand about John Q. Public in the example.

How to use your personal mind map

This is a great way to have team or project members introduce themselves to each other. You can apply all sorts of formatting and color to the map to give it personality. These are fun to do on paper, of course. But having one on your Fedora system means you can always fix mistakes, or even make changes as you change.

Have fun exploring your personal mind map!


Photo by Daniel Hjalmarsson on Unsplash.

post

Build a Django RESTful API on Fedora.

With the rise of kubernetes and micro-services architecture, being able to quickly write and deploy a RESTful API service is a good skill to have. In this first part of a series of articles, you’ll learn how to use Fedora to build a RESTful application and deploy it on Openshift. Together, we’re going to build the back-end for a “To Do” application.

The APIs allow you to Create, Read, Update, and Delete (CRUD) a task. The tasks are stored in a database and we’re using the Django ORM (Object Relational Mapping) to deal with the database management.

Django App and Rest Framework setup

In a new directory, create a Python 3 virtual environment so that you can install dependencies.

$ mkdir todoapp && cd todoapp
$ python3 -m venv .venv
$ source .venv/bin/activate

After activating the virtual environment, install the dependencies.

(.venv)$ pip install djangorestframework django

Django REST Framework, or DRF, is a framework that makes it easy to create RESTful CRUD APIs. By default it gives access to useful features like browseable APIs, authentication management, serialization of data, and more.

Create the Django project and application

Create the Django project using the django-admin CLI tool provided.

(.venv) $ django-admin startproject todo_app . # Note the trailing '.'
(.venv) $ tree .
.
├── manage.py
└── todo_app
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py
1 directory, 5 files

Next, create the application inside the project.

(.venv) $ cd todo_app
(.venv) $ django-admin startapp todo
(.venv) $ cd ..
(.venv) $ tree .
.
├── manage.py
└── todo_app
├── __init__.py
├── settings.py
├── todo
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── urls.py
└── wsgi.py

Now that the basic structure of the project is in place, you can enable the REST framework and the todo application. Let’s add rest_framework and todo to the list of INSTALL_APPS in the project’s settings.py.

todoapp/todo_app/settings.py
# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'todo_app.todo',
]

 Application Model and Database

The next step of building our application is to set up the database. By default, Django uses the SQLite database management system. Since SQLite works well and is easy to use during development, let’s keep this default setting. The second part of this series will look at how to replace SQLite with PostgreSQL to run the application in production.

The Task Model

By adding the following code to todo_app/todo/models.py, you define which properties have a task. The application defines a task with a title, description and a status. The status of a task can only be one of the three following states: Backlog, Work in Progress and Done.

from django.db import models

class Task(models.Model):
STATES = (("todo", "Backlog"), ("wip", "Work in Progress"), ("done", "Done"))
title = models.CharField(max_length=255, blank=False, unique=True)
description = models.TextField()
status = models.CharField(max_length=4, choices=STATES, default="todo")

Now create the database migration script that Django uses to update the database with changes.

(.venv) $ PYTHONPATH=. DJANGO_SETTINGS_MODULE=todo_app.settings django-admin makemigrations

Then you can apply the migration to the database.

(.venv) $ PYTHONPATH=. DJANGO_SETTINGS_MODULE=todo_app.settings django-admin migrate

This step creates a file named db.sqlite3 in the root directory of the application. This is where SQLite stores the data.

Access to the data

Creating a View

Now that you can represent and store a task in the database, you need a way to access the data.  This is where we start making use of Django REST Framework by using the ModelViewSet. The ModelViewSet provides the following actions on a data model: list, retrieve, create, update, partial update, and destroy.

Let’s add our view to todo_app/todo/views.py:

from rest_framework import viewsets

from todo_app.todo.models import Task
from todo_app.todo.serializers import TaskSerializer


class TaskViewSet(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer

Creating a Serializer

As you can see, the TaskViewSet is using a Serializer. In DRF, serializers convert the data modeled in the application models to a native Python datatype. This datatype can be later easily rendered into JSON or XML, for example. Serializers are also used to deserialize JSON or other content types into the data structure defined in the model.

Let’s add our TaskSerializer object by creating a new file in the project todo_app/todo/serializers.py:

from rest_framework.serializers import ModelSerializer
from todo_app.todo.models import Task


class TaskSerializer(ModelSerializer):
class Meta:
model = Task
fields = "__all__"

We’re using the generic ModelSerializer from DRF, to automatically create a serializer with the fields that correspond to our Task model.

Now that we have a data model a view and way to serialize/deserialize data, we need to map our view actions to URLs. That way we can use HTTP methods to manipulate our data.

Creating a Router

Here again we’re using the power of the Django REST Framework with the DefaultRouter. The DRF DefaultRouter takes care of mapping actions to HTTP Method and URLs.

Before we see a better example of what the DefaultRouter does for us, let’s add a new URL to access the view we have created earlier. Add the following to todo_app/urls.py:

from django.contrib import admin
from django.conf.urls import url, include

from rest_framework.routers import DefaultRouter

from todo_app.todo.views import TaskViewSet

router = DefaultRouter()
router.register(r"todo", TaskViewSet)

urlpatterns = [
url(r"admin/", admin.site.urls),
url(r"^api/", include((router.urls, "todo"))),
]

As you can see, we’re registering our TaskViewSet to the DefaultRouter. Then later, we’re mapping all the router URLs to the /api endpoint. This way, DRF takes care of mapping the URLs and HTTP method to our view actions (list, retrieve, create, update, destroy).

For example, accessing the api/todo endpoint with a GET HTTP request calls the list action of our view. Doing the same but using a POST HTTP request calls the create action.

To get a better grasp of this, let’s run the application and start using our API.

Running the application

We can run the application using the development server provided by Django. This server should only be used during development. We’ll see in the second part of this tutorial how to use a web server better suited for production.

(.venv)$ PYTHONPATH=. DJANGO_SETTINGS_MODULE=todo_app.settings django-admin runserver
Django version 2.1.5, using settings 'todo_app.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Now we can access the application at the following URL: http://127.0.0.1:8000/api/

DRF provides an interface to the view actions, for example listing or creating tasks, using the following URL: http://127.0.0.1:8000/api/todo

Or updating/deleting an existing tasks with this URL: http://127.0.0.1:8000/api/todo/1

Conclusion

In this article you’ve learned how to create a basic RESTful API using the Django REST Framework. In the second part of this series, we’ll update this application to use the PostgreSQL database management system, and deploy it in OpenShift.

The source code of the application is available on GitHub.

post

How to Build a Netboot Server, Part 4

One significant limitation of the netboot server built in this series is the operating system image being served is read-only. Some use cases may require the end user to modify the image. For example, an instructor may want to have the students install and configure software packages like MariaDB and Node.js as part of their course walk-through.

An added benefit of writable netboot images is the end user’s “personalized” operating system can follow them to different workstations they may use at later times.

Change the Bootmenu Application to use HTTPS

Create a self-signed certificate for the bootmenu application:

$ sudo -i
# MY_NAME=$(</etc/hostname)
# MY_TLSD=/opt/bootmenu/tls
# mkdir $MY_TLSD
# openssl req -newkey rsa:2048 -nodes -keyout $MY_TLSD/$MY_NAME.key -x509 -days 3650 -out $MY_TLSD/$MY_NAME.pem

Verify your certificate’s values. Make sure the “CN” value in the “Subject” line matches the DNS name that your iPXE clients use to connect to your bootmenu server:

# openssl x509 -text -noout -in $MY_TLSD/$MY_NAME.pem

Next, update the bootmenu application’s listen directive to use the HTTPS port and the newly created certificate and key:

# sed -i "s#listen => .*#listen => ['https://$MY_NAME:443?cert=$MY_TLSD/$MY_NAME.pem\&key=$MY_TLSD/$MY_NAME.key\&ciphers=AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA'],#" /opt/bootmenu/bootmenu.conf

Note the ciphers have been restricted to those currently supported by iPXE.

GnuTLS requires the “CAP_DAC_READ_SEARCH” capability, so add it to the bootmenu application’s systemd service:

# sed -i '/^AmbientCapabilities=/ s/$/ CAP_DAC_READ_SEARCH/' /etc/systemd/system/bootmenu.service
# sed -i 's/Serves iPXE Menus over HTTP/Serves iPXE Menus over HTTPS/' /etc/systemd/system/bootmenu.service
# systemctl daemon-reload

Now, add an exception for the bootmenu service to the firewall and restart the service:

# MY_SUBNET=192.0.2.0
# MY_PREFIX=24
# firewall-cmd --add-rich-rule="rule family='ipv4' source address='$MY_SUBNET/$MY_PREFIX' service name='https' accept"
# firewall-cmd --runtime-to-permanent
# systemctl restart bootmenu.service

Use wget to verify it’s working:

$ MY_NAME=server-01.example.edu
$ MY_TLSD=/opt/bootmenu/tls
$ wget -q --ca-certificate=$MY_TLSD/$MY_NAME.pem -O - https://$MY_NAME/menu

Add HTTPS to iPXE

Update init.ipxe to use HTTPS. Then recompile the ipxe bootloader with options to embed and trust the self-signed certificate you created for the bootmenu application:

$ echo '#define DOWNLOAD_PROTO_HTTPS' >> $HOME/ipxe/src/config/local/general.h
$ sed -i 's/^chain http:/chain https:/' $HOME/ipxe/init.ipxe
$ cp $MY_TLSD/$MY_NAME.pem $HOME/ipxe
$ cd $HOME/ipxe/src
$ make clean
$ make bin-x86_64-efi/ipxe.efi EMBED=../init.ipxe CERT="../$MY_NAME.pem" TRUST="../$MY_NAME.pem"

You can now copy the HTTPS-enabled iPXE bootloader out to your clients and test that everything is working correctly:

$ cp $HOME/ipxe/src/bin-x86_64-efi/ipxe.efi $HOME/esp/efi/boot/bootx64.efi

Add User Authentication to Mojolicious

Create a PAM service definition for the bootmenu application:

# dnf install -y pam_krb5
# echo 'auth required pam_krb5.so' > /etc/pam.d/bootmenu

Add a library to the bootmenu application that uses the Authen-PAM perl module to perform user authentication:

# dnf install -y perl-Authen-PAM;
# MY_MOJO=/opt/bootmenu
# mkdir $MY_MOJO/lib
# cat << 'END' > $MY_MOJO/lib/PAM.pm
package PAM; use Authen::PAM; sub auth { my $success = 0; my $username = shift; my $password = shift; my $callback = sub { my @res; while (@_) { my $code = shift; my $msg = shift; my $ans = ""; $ans = $username if ($code == PAM_PROMPT_ECHO_ON()); $ans = $password if ($code == PAM_PROMPT_ECHO_OFF()); push @res, (PAM_SUCCESS(), $ans); } push @res, PAM_SUCCESS(); return @res; }; my $pamh = new Authen::PAM('bootmenu', $username, $callback); { last unless ref $pamh; last unless $pamh->pam_authenticate() == PAM_SUCCESS; $success = 1; } return $success;
} return 1;
END

The above code is taken almost verbatim from the Authen::PAM::FAQ man page.

Redefine the bootmenu application so it returns a netboot template only if a valid username and password are supplied:

# cat << 'END' > $MY_MOJO/bootmenu.pl
#!/usr/bin/env perl use lib 'lib'; use PAM;
use Mojolicious::Lite;
use Mojolicious::Plugins;
use Mojo::Util ('url_unescape'); plugin 'Config'; get '/menu';
get '/boot' => sub { my $c = shift; my $instance = $c->param('instance'); my $username = $c->param('username'); my $password = $c->param('password'); my $template = 'menu'; { last unless $instance =~ /^fc[[:digit:]]{2}$/; last unless $username =~ /^[[:alnum:]]+$/; last unless PAM::auth($username, url_unescape($password)); $template = $instance; } return $c->render(template => $template);
}; app->start;
END

The bootmenu application now looks for the lib directory relative to its WorkingDirectory. However, by default the working directory is set to the root directory of the server for systemd units. Therefore, you must update the systemd unit to set WorkingDirectory to the root of the bootmenu application instead:

# sed -i "/^RuntimeDirectory=/ a WorkingDirectory=$MY_MOJO" /etc/systemd/system/bootmenu.service
# systemctl daemon-reload

Update the templates to work with the redefined bootmenu application:

# cd $MY_MOJO/templates
# MY_BOOTMENU_SERVER=$(</etc/hostname)
# MY_FEDORA_RELEASES="28 29"
# for i in $MY_FEDORA_RELEASES; do echo '#!ipxe' > fc$i.html.ep; grep "^kernel\|initrd" menu.html.ep | grep "fc$i" >> fc$i.html.ep; echo "boot || chain https://$MY_BOOTMENU_SERVER/menu" >> fc$i.html.ep; sed -i "/^:f$i$/,/^boot /c :f$i\nlogin\nchain https://$MY_BOOTMENU_SERVER/boot?instance=fc$i\&username=\${username}\&password=\${password:uristring} || goto failed" menu.html.ep; done

The result of the last command above should be three files similar to the following:

menu.html.ep:

#!ipxe set timeout 5000 :menu
menu iPXE Boot Menu
item --key 1 lcl 1. Microsoft Windows 10
item --key 2 f29 2. RedHat Fedora 29
item --key 3 f28 3. RedHat Fedora 28
choose --timeout ${timeout} --default lcl selected || goto shell
set timeout 0
goto ${selected} :failed
echo boot failed, dropping to shell...
goto shell :shell
echo type 'exit' to get the back to the menu
set timeout 0
shell
goto menu :lcl
exit :f29
login
chain https://server-01.example.edu/boot?instance=fc29&username=${username}&password=${password:uristring} || goto failed :f28
login
chain https://server-01.example.edu/boot?instance=fc28&username=${username}&password=${password:uristring} || goto failed

fc29.html.ep:

#!ipxe
kernel --name kernel.efi ${prefix}/vmlinuz-4.19.5-300.fc29.x86_64 initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=192.0.2.91 nameserver=192.0.2.92 root=/dev/disk/by-path/ip-192.0.2.158:3260-iscsi-iqn.edu.example.server-01:fc29-lun-1 netroot=iscsi:192.0.2.158::::iqn.edu.example.server-01:fc29 console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
initrd --name initrd.img ${prefix}/initramfs-4.19.5-300.fc29.x86_64.img
boot || chain https://server-01.example.edu/menu

fc28.html.ep:

#!ipxe
kernel --name kernel.efi ${prefix}/vmlinuz-4.19.3-200.fc28.x86_64 initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=192.0.2.91 nameserver=192.0.2.92 root=/dev/disk/by-path/ip-192.0.2.158:3260-iscsi-iqn.edu.example.server-01:fc28-lun-1 netroot=iscsi:192.0.2.158::::iqn.edu.example.server-01:fc28 console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
initrd --name initrd.img ${prefix}/initramfs-4.19.3-200.fc28.x86_64.img
boot || chain https://server-01.example.edu/menu

Now, restart the bootmenu application and verify authentication is working:

# systemctl restart bootmenu.service

Make the iSCSI Target Writeable

Now that user authentication works through iPXE, you can create per-user, writeable overlays on top of the read-only image on demand when users connect. Using a copy-on-write overlay has three advantages over simply copying the original image file for each user:

  1. The copy can be created very quickly. This allows creation on-demand.
  2. The copy does not increase the disk usage on the server. Only what the user writes to their personal copy of the image is stored in addition to the original image.
  3. Since most sectors for each copy are the same sectors on the server’s storage, they’ll likely already be loaded in RAM when subsequent users access their copies of the operating system. This improves the server’s performance because RAM is faster than disk I/O.

One potential pitfall of using copy-on-write is that once overlays are created, the images on which they are overlayed must not be changed. If they are changed, all the overlays will be corrupted. Then the overlays must be deleted and replaced with new, blank overlays. Even simply mounting the image file in read-write mode can cause sufficient filesystem updates to corrupt the overlays.

Due to the potential for the overlays to be corrupted if the original image is modified, mark the original image as immutable by running:

# chattr +i </path/to/file>

You can use lsattr </path/to/file> to view the status of the immutable flag and use  to chattr -i </path/to/file> unset the immutable flag. While the immutable flag is set, even the root user or a system process running as root cannot modify or delete the file.

Begin by stopping the tgtd.service so you can change the image files:

# systemctl stop tgtd.service

It’s normal for this command to take a minute or so to stop when there are connections still open.

Now, remove the read-only iSCSI export. Then update the readonly-root configuration file in the template so the image is no longer read-only:

# MY_FC=fc29
# rm -f /etc/tgt/conf.d/$MY_FC.conf
# TEMP_MNT=$(mktemp -d)
# mount /$MY_FC.img $TEMP_MNT
# sed -i 's/^READONLY=yes$/READONLY=no/' $TEMP_MNT/etc/sysconfig/readonly-root
# sed -i 's/^Storage=volatile$/#Storage=auto/' $TEMP_MNT/etc/systemd/journald.conf
# umount $TEMP_MNT

Journald was changed from logging to volatile memory back to its default (log to disk if /var/log/journal exists) because a user reported his clients would freeze with an out-of-memory error due to an application generating excessive system logs. The downside to setting logging to disk is that extra write traffic is generated by the clients, and might burden your netboot server with unnecessary I/O. You should decide which option — log to memory or log to disk — is preferable depending on your environment.

Since you won’t make any further changes to the template image, set the immutable flag on it and restart the tgtd.service:

# chattr +i /$MY_FC.img
# systemctl start tgtd.service

Now, update the bootmenu application:

# cat << 'END' > $MY_MOJO/bootmenu.pl
#!/usr/bin/env perl use lib 'lib'; use PAM;
use Mojolicious::Lite;
use Mojolicious::Plugins;
use Mojo::Util ('url_unescape'); plugin 'Config'; get '/menu';
get '/boot' => sub { my $c = shift; my $instance = $c->param('instance'); my $username = $c->param('username'); my $password = $c->param('password'); my $chapscrt; my $template = 'menu'; { last unless $instance =~ /^fc[[:digit:]]{2}$/; last unless $username =~ /^[[:alnum:]]+$/; last unless PAM::auth($username, url_unescape($password)); last unless $chapscrt = `sudo scripts/mktgt $instance $username`; $template = $instance; } return $c->render(template => $template, username => $username, chapscrt => $chapscrt);
}; app->start;
END

This new version of the bootmenu application calls a custom mktgt script which, on success, returns a random CHAP password for each new iSCSI target that it creates. The CHAP password prevents one user from mounting another user’s iSCSI target by indirect means. The app only returns the correct iSCSI target password to a user who has successfully authenticated.

The mktgt script is prefixed with sudo because it needs root privileges to create the target.

The $username and $chapscrt variables also pass to the render command so they can be incorporated into the templates returned to the user when necessary.

Next, update our boot templates so they can read the username and chapscrt variables and pass them along to the end user. Also update the templates to mount the root filesystem in rw (read-write) mode:

# cd $MY_MOJO/templates
# sed -i "s/:$MY_FC/:$MY_FC-<%= \$username %>/g" $MY_FC.html.ep
# sed -i "s/ netroot=iscsi:/ netroot=iscsi:<%= \$username %>:<%= \$chapscrt %>@/" $MY_FC.html.ep
# sed -i "s/ ro / rw /" $MY_FC.html.ep

After running the above commands, you should have boot templates like the following:

#!ipxe
kernel --name kernel.efi ${prefix}/vmlinuz-4.19.5-300.fc29.x86_64 initrd=initrd.img rw ip=dhcp rd.peerdns=0 nameserver=192.0.2.91 nameserver=192.0.2.92 root=/dev/disk/by-path/ip-192.0.2.158:3260-iscsi-iqn.edu.example.server-01:fc29-<%= $username %>-lun-1 netroot=iscsi:<%= $username %>:<%= $chapscrt %>@192.0.2.158::::iqn.edu.example.server-01:fc29-<%= $username %> console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
initrd --name initrd.img ${prefix}/initramfs-4.19.5-300.fc29.x86_64.img
boot || chain https://server-01.example.edu/menu

NOTE: If you need to view the boot template after the variables have been interpolated, you can insert the “shell” command on its own line just before the “boot” command. Then, when you netboot your client, iPXE gives you an interactive shell where you can enter “imgstat” to view the parameters being passed to the kernel. If everything looks correct, you can type “exit” to leave the shell and continue the boot process.

Now allow the bootmenu user to run the mktgt script (and only that script) as root via sudo:

# echo "bootmenu ALL = NOPASSWD: $MY_MOJO/scripts/mktgt *" > /etc/sudoers.d/bootmenu

The bootmenu user should not have write access to the mktgt script or any other files under its home directory. All the files under /opt/bootmenu should be owned by root, and should not be writable by any user other than root.

Sudo does not work well with systemd’s DynamicUser option, so create a normal user account and set the systemd service to run as that user:

# useradd -r -c 'iPXE Boot Menu Service' -d /opt/bootmenu -s /sbin/nologin bootmenu
# sed -i 's/^DynamicUser=true$/User=bootmenu/' /etc/systemd/system/bootmenu.service
# systemctl daemon-reload

Finally, create a directory for the copy-on-write overlays and create the mktgt script that manages the iSCSI targets and their overlayed backing stores:

# mkdir /$MY_FC.cow
# mkdir $MY_MOJO/scripts
# cat << 'END' > $MY_MOJO/scripts/mktgt
#!/usr/bin/env perl # if another instance of this script is running, wait for it to finish "$ENV{FLOCKER}" eq 'MKTGT' or exec "env FLOCKER=MKTGT flock /tmp $0 @ARGV"; # use "RETURN" to print to STDOUT; everything else goes to STDERR by default
open(RETURN, '>&', STDOUT);
open(STDOUT, '>&', STDERR); my $instance = shift or die "instance not provided";
my $username = shift or die "username not provided"; my $img = "/$instance.img";
my $dir = "/$instance.cow";
my $top = "$dir/$username"; -f "$img" or die "'$img' is not a file"; -d "$dir" or die "'$dir' is not a directory"; my $base;
die unless $base = `losetup --show --read-only --nooverlap --find $img`;
chomp $base; my $size;
die unless $size = `blockdev --getsz $base`;
chomp $size; # create the per-user sparse file if it does not exist
if (! -e "$top") { die unless system("dd if=/dev/zero of=$top status=none bs=512 count=0 seek=$size") == 0;
} # create the copy-on-write overlay if it does not exist
my $cow="$instance-$username";
my $dev="/dev/mapper/$cow";
if (! -e "$dev") { my $over; die unless $over = `losetup --show --nooverlap --find $top`; chomp $over; die unless system("echo 0 $size snapshot $base $over p 8 | dmsetup create $cow") == 0;
} my $tgtadm = '/usr/sbin/tgtadm --lld iscsi'; # get textual representations of the iscsi targets
my $text = `$tgtadm --op show --mode target`;
my @targets = $text =~ /(?:^T.*\n)(?:^ .*\n)*/mg; # convert the textual representations into a hash table
my $targets = {};
foreach (@targets) { my $tgt; my $sid; foreach (split /\n/) { /^Target (\d+)(?{ $tgt = $targets->{$^N} = [] })/; /I_T nexus: (\d+)(?{ $sid = $^N })/; /Connection: (\d+)(?{ push @{$tgt}, [ $sid, $^N ] })/; }
} my $hostname;
die unless $hostname = `hostname`;
chomp $hostname; my $target = 'iqn.' . join('.', reverse split('\.', $hostname)) . ":$cow"; # find the target id corresponding to the provided target name and
# close any existing connections to it
my $tid = 0;
foreach (@targets) { next unless /^Target (\d+)(?{ $tid = $^N }): $target$/m; foreach (@{$targets->{$tid}}) { die unless system("$tgtadm --op delete --mode conn --tid $tid --sid $_->[0] --cid $_->[1]") == 0; }
} # create a new target if an existing one was not found
if ($tid == 0) { # find an available target id my @ids = (0, sort keys %{$targets}); $tid = 1; while ($ids[$tid]==$tid) { $tid++ } # create the target die unless -e "$dev"; die unless system("$tgtadm --op new --mode target --tid $tid --targetname $target") == 0; die unless system("$tgtadm --op new --mode logicalunit --tid $tid --lun 1 --backing-store $dev") == 0; die unless system("$tgtadm --op bind --mode target --tid $tid --initiator-address ALL") == 0;
} # (re)set the provided target's chap password
my $password = join('', map(chr(int(rand(26))+65), 1..8));
my $accounts = `$tgtadm --op show --mode account`;
if ($accounts =~ / $username$/m) { die unless system("$tgtadm --op delete --mode account --user $username") == 0;
}
die unless system("$tgtadm --op new --mode account --user $username --password $password") == 0;
die unless system("$tgtadm --op bind --mode account --tid $tid --user $username") == 0; # return the new password to the iscsi target on stdout
print RETURN $password;
END
# chmod +x $MY_MOJO/scripts/mktgt

The above script does five things:

  1. It creates the /<instance>.cow/<username> sparse file if it does not already exist.
  2. It creates the /dev/mapper/<instance>-<username> device node that serves as the copy-on-write backing store for the iSCSI target if it does not already exist.
  3. It creates the iqn.<reverse-hostname>:<instance>-<username> iSCSI target if it does not exist. Or, if the target does exist, it closes any existing connections to it because the image can only be opened in read-write mode from one place at a time.
  4. It (re)sets the chap password on the iqn.<reverse-hostname>:<instance>-<username> iSCSI target to a new random value.
  5. It prints the new chap password on standard output if all of the previous tasks compeleted successfully.

You should be able to test the mktgt script from the command line by running it with valid test parameters. For example:

# echo `$MY_MOJO/scripts/mktgt fc29 jsmith`

When run from the command line, the mktgt script should print out either the eight-character random password for the iSCSI target if it succeeded or the line number on which something went wrong if it failed.

On occasion, you may want to delete an iSCSI target without having to stop the entire service. For example, a user might inadvertently corrupt their personal image, in which case you would need to systematically undo everything that the above mktgt script does so that the next time they log in they will get a copy of the original image.

Below is an rmtgt script that undoes, in reverse order, what the above mktgt script did:

# mkdir $HOME/bin
# cat << 'END' > $HOME/bin/rmtgt
#!/usr/bin/env perl @ARGV >= 2 or die "usage: $0 <instance> <username> [+d|+f]\n"; my $instance = shift;
my $username = shift; my $rmd = ($ARGV[0] eq '+d'); #remove device node if +d flag is set
my $rmf = ($ARGV[0] eq '+f'); #remove sparse file if +f flag is set
my $cow = "$instance-$username"; my $hostname;
die unless $hostname = `hostname`;
chomp $hostname; my $tgtadm = '/usr/sbin/tgtadm';
my $target = 'iqn.' . join('.', reverse split('\.', $hostname)) . ":$cow"; my $text = `$tgtadm --op show --mode target`;
my @targets = $text =~ /(?:^T.*\n)(?:^ .*\n)*/mg; my $targets = {};
foreach (@targets) { my $tgt; my $sid; foreach (split /\n/) { /^Target (\d+)(?{ $tgt = $targets->{$^N} = [] })/; /I_T nexus: (\d+)(?{ $sid = $^N })/; /Connection: (\d+)(?{ push @{$tgt}, [ $sid, $^N ] })/; }
} my $tid = 0;
foreach (@targets) { next unless /^Target (\d+)(?{ $tid = $^N }): $target$/m; foreach (@{$targets->{$tid}}) { die unless system("$tgtadm --op delete --mode conn --tid $tid --sid $_->[0] --cid $_->[1]") == 0; } die unless system("$tgtadm --op delete --mode target --tid $tid") == 0; print "target $tid deleted\n"; sleep 1;
} my $dev = "/dev/mapper/$cow";
if ($rmd or ($rmf and -e $dev)) { die unless system("dmsetup remove $cow") == 0; print "device node $dev deleted\n";
} if ($rmf) { my $sf = "/$instance.cow/$username"; die "sparse file $sf not found" unless -e "$sf"; die unless system("rm -f $sf") == 0; die unless not -e "$sf"; print "sparse file $sf deleted\n";
}
END
# chmod +x $HOME/bin/rmtgt

For example, to use the above script to completely remove the fc29-jsmith target including its backing store device node and its sparse file, run the following:

# rmtgt fc29 jsmith +f

Once you’ve verified that the mktgt script is working properly, you can restart the bootmenu service. The next time someone netboots, they should receive a personal copy of the the netboot image they can write to:

# systemctl restart bootmenu.service

Users should now be able to modify the root filesystem as demonstrated in the below screenshot: