Sommerhitze & Powershell 3 kleine Tipps

Hallo Netways Follower,

Ich melde mich dies mal mit einem kurzen aber meist vergessenen Thema nämlich wie kriegt man unter Windows diese vermaledeiten Powershell Skripts korrekt zum laufen.

Wenn man bei einem normalen Icinga2 Windows Agenten diese in ‘Betrieb’ nehmen will benötigt es etwas Handarbeit und Schweiß bei diesen Sommertagen um dies zu bewerkstelligen.

Trotzdem hier ein paar Tipps:

1) Tipp “Powershell Skripte sollten ausführbar sein”

Nachdem der Windows Agent installiert und funktional ist sollte man sich auf der Windows Maschine wo man das Powershell Skript ausführen möchte in die Powershell (nicht vergessen mit Administrativer Berechtigung) begeben.

Um Powershell Skripts ausführen zu können muss dies erst aktiviert werden dazu gibt es das folgende Kommando

Set-ExecutionPolicy Unrestricted
Set-ExecutionPolicy RemoteSigned
Set-ExecutionPolicy Restricted

Hier sollte zumeist RemoteSigned ausreichend sein, aber es kommt wie immer auf den Anwendungsfall an. More Info here.

Nach der Aktivierung kann man nun überprüfen ob man Powershell Skripts ausführen kann.
Hierzu verwende ich meist das Notepad um folgendes zu schreiben um anschließend zu prüfen ob das oben aktivierte auch klappt.

Also ein leeres Windows Notepad mit dem folgenden befüllen:

Write-Host "Ash nazg durbatulûk, ash nazg gimbatul, ash nazg thrakatulûk agh burzum-ishi krimpatul. "

Das ganze dann als ‘test.ps1’ speichern.

Nun wieder in die Powershell zurück und an dem Platz wo man das Powershell Skript gespeichert hat es mit dem folgenden Kommando aufrufen.
PS C:\Users\dave\Desktop> & .\test.ps1
Ash nazg durbatulûk, ash nazg gimbatul, ash nazg thrakatulûk agh burzum-ishi krimpatul.

Sollte als Ergebnis angezeigt werden damit Powershell Skripts ausführbar sind.

2) Tipp “Das Icinga2 Agent Plugin Verzeichnis”

In der Windows Version unseres Icinga2 Agents ist das standard Plugin Verzeichnis folgendes:
PS C:\Program Files\ICINGA2\sbin>

Hier liegen auch die Windows Check Executables.. und ‘.ps1’ Skripte welche auf dem Host ausgeführt werden sollten/müssen auch hier liegen.

3) Tipp “Powershell 32Bit & 64Bit”

Wenn ein Skript relevante 64Bit Sachen erledigen muss kann auch die 64er Version explizit verwendet werden in den Check aufrufen.

Das heißt wenn man den object CheckCommand “Mein Toller Check” definiert kann man in dem Setting:

command = [ "C:\\Windows\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe" ] //als 64 Bit angeben und
command = [ "C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe" ] // als 32Bit.

Hoffe die drei kleinen Tipps erleichtern das Windows Monitoring mit Powershell Skripts.
Wenn hierzu noch Fragen aufkommen kann ich unser Community Forum empfehlen und den ‘kleinen’ Guide von unserem Kollegen Michael. Icinga Community Forums

Ich sag Ciao bis zum nächsten Mal.

David Okon
David Okon
Senior Consultant

Weltenbummler David hat aus Berlin fast den direkten Weg zu uns nach Nürnberg genommen. Bevor er hier anheuerte, gab es einen kleinen Schlenker nach Irland, England, Frankreich und in die Niederlande. Alles nur, damit er sein Know How als IHK Geprüfter DOSenöffner so sehr vertiefen konnte, dass er vom Apple Consultant den Sprung in unser Professional Services-Team wagen konnte. Er ist stolzer Papa eines Sohnemanns und bei uns mit der Mission unterwegs, unsere Kunden zu...

Python lernen?

Hier möchte ich meine Erfahrung teilen, wie ich in die Sprache Python eingestiegen bin.

 

Am Anfang der Ausbildung bin ich in PHP eingestiegen und fand die Sprache sehr angenehm.

Dazu gehören natürlich auch die Auszeichnungs-, Definitionsprachen HTML & CSS.

Doch mit der Zeit wurde PHP für mich als Programmier-Neuling immer komplexer.

Im Hinterkopf behielt ich Python, weil ich immer wieder von Programmierern hörte wie einfach diese Sprache sei

und diese auch von ihnen empfohlen wurde.

Zudem soll sie einer der beliebtesten und sehr gut für Beginner sein.

Also was spricht dagegen sie zu lernen?          Richtig. Gar nichts.

Aber wie lernt man eine Programmiersprache? 

Durch Blogs? Durch Videokurse?  Durch Bücher?

Der eine findet Videokurse gut, der andere Blogs und reinen Text. Das ist ganz ok.

Solange man Fortschritte macht, macht man nichts falsch.

Ehrlich gesagt muss man für sich selber herausfinden wie man am besten lernen kann.

Vielleicht mal alle Lernangebote durchstöbern und dann entscheiden was passt.

Ich persönlich habe Bücher sehr in mein Herz eingeschlossen. Ein Grund:

Das Buch liegt direkt vor einem. Videokurse sind etwas umständlicher.

Also habe ich mir ein Buch geholt. Sogar ein sehr gutes von O’REILLY.

Es ist echt wichtig das in einem Buch alles ausführlich erklärt wird. In dem Fall tut es das Buch.

Und wie komme ich mit der Sprache zurecht?

Anders als bei der anderen Sprachen gibt es eine kleine Umstellung.

Und zwar sind die Einrückungen (die Suiten) sehr wichtig. Da wird gleich die Syntax mit geübt.

Daran muss man sich erst gewöhnen. Sonst komme ich zurzeit gut zurecht.

So möchte ich mir mit Python ein weiteres Fundament aufbauen.

Ich kann Python nur weiter empfehlen!

Loei Petrus Marogi
Loei Petrus Marogi
Junior Developer

Loei ist Fachinformatik-Azubi im ersten Lehrjahr und lernt momentan unseren Toolstack kennen. Nach der Linux-Schulung freut er sich besonders aufs Programmieren. Wenn er mal nicht bei NETWAYS ist, spielt er Fußball im Verein oder geht ins Fitnessstudio.
How to: Merge multiple Git repositories into one

How to: Merge multiple Git repositories into one

Some time ago, I worked on a project that was split into multiple Git repositories. After a few weeks we decided, that it wasn’t longer necessary to have multiple repositories for this project, so we decided to merge them. The question was, if it is possible to merge multiple code bases without losing their history. The answer is yes. We have two ways on how to tackle this. The first way uses one of the repositories as the new main repository. The second option is to create a new repository for that purpose. We chose option one, because we already had a repository that acted as the main repository. If you choose to create a new repository, you can still follow the steps below. The only difference is, that you need at least one commit on that new repository, to be able to merge into it.

Preparation:
Before merging our repositories, we might first have to do some preparation on them. To prevent merge conflicts, you could move all files into a new directory, before merging them.

# Create a new directory
mkdir repo1
# Move all files into repo1
mv * repo1
# Commit those changes
git commit -am "Prepare for repository merge"
# Push changes to origin
git push

When thats done, add the repository as a remote on the new main repository.

git remote add repo1 git@git.example.com:project/repo1.git

The merge:
After that the merge is quite simple. We just have to append --allow-unrelated-histories to allow the merge of unrelated code bases.

git merge repo1/master --allow-unrelated-histories

If thats successful, the merge is done.

Redo the steps above for every repository you want to merge.

Noah Hilverling
Noah Hilverling
Junior Developer

Nachdem Noah bei einer vierjährigen Exkursion nach Belgien seine Liebe zum Programmieren entdeckte, holte der gebürtige Euskirchener innerhalb kürzester Zeit gleich zwei Schulabschlüsse nach. Danach verließ Noah sogar den schönen Chiemsee, um sich ab September 2016 im Rahmen der Ausbildung zum Fachinformatiker für Anwendungsentwicklung bei NETWAYS voll und ganz dem Programmieren hinzugeben und viele unterschiedliche Erfahrungen zu sammeln. Wenn er mal nicht am Programmieren und Zocken ist, brettert er mit seinem Snowboard die Pisten runter,...

It all started with a GameBoy

It’s time to reflect and talk about video games. On how I got into programming and what drives me.

MissingNo: The glitch, the legend, my beginnings

Catch them all!

Pokémon, the first generation Game Boy games. They were the first thing that made me wonder just how programs and computers work. Back in the late 20th and early 21th century Pokémon Red and Blue were the talk of the schoolyard, if you are Generation X or a Millennial you probably know what I’m talking about. Fake rumors on how to get the rarest monsters with absurd guides were floating around: Do X while Y and have two of Z but don’t feed them after midnight. What gave these urban legends credibility were bugs in the games which had seemingly unrelated steps lead to weird and for a child even scary results – from characters being cut up and incorrectly reassembled over save games becoming unusable to a constant, never ending screaming sound.

For those who have not played these classics, I’m talking about the now famous MissingNo Glitch. Now we know the bug is caused by incorrect read and writes in the game. The games were written in Assembly and the programmers had very limited memory and space to work with, something was bound to break and such bugs are not uncommon in early console games. Most kids were just happy to have an infinite supply of Master Balls, an item in the game that could only be acquired once in the game, or get their favorite monster to the highest level quickly. For me this was enough at first as well but as time went on I grew more and more intrigued by the bug.

Minus World. A well known bug caused by incorrectly loading a level.

I asked my dad, he had no clue and neither did my mom.The internet was hard to use then still and I did not find my answers then. What I found was more confusing information and ways to manipulate the game, mostly collected by trial and error of other players, but there were also mentions of buffer overruns, memory violation and other terms I could not make sense of and didn’t hear again until I was allowed to watch The Matrix. This knowledge of the games made me the coolest kid on the playground for a while at least.

And after the Elite Four?

Only when I joined the local hackerspace and got involved with the CCC I finally got my entry point to the world of computers and programming. There was referred the book Learn Python The Hard Way and started writing code. Sadly none of my early work exists anymore, of git and GitHub I learned later still. The obvious choice then was to go to Uni and sign up for Computer Science class, three semesters I spent trying to wrap my head around the math needed to pass but ultimately quit because of it.

But my interest in programming was unbroken, I loved classes like Systems Programming which had assignments where you had to implement basic tools yourself, my own shell, my own email server, netcat – everything in C of course. That’s when I found my way to NETWAYS as an apprentice and have stayed here since, they let me write code. The code I write has changed, abstraction and new languages like Go have changed how I program but the lessons I learned from playing Pokémon in my bedroom still hold true: Sometimes it takes time to understand a bug.

If you’d like to join me in hunting bugs or talking retro games over a cup of coffee, head on over to our jobs page!



Diana Flach
Diana Flach
Developer

Geboren und aufgewachsen in Bamberg kam Diana, nach einem Ausflug an die Uni, als Azubi zu NETWAYS. Dort sitzt sie seit 2014 im Icinga 2 Core Entwicklungsteam.

Verschachtelte Listen mit Sortable.js

Nachdem ich vor einiger Zeit die Ehre hatte Drag & Drop im Business Process Modul für Icinga Web 2 zu integrieren, dachte ich mir ich plaudere heute mal ein wenig aus dem Nähkästchen welche Stolpersteine ich dabei überwinden musste.

Aber erst einmal eine kleine Vorstellung der Bibliothek die eingesetzt wurde: Sortable.js 

Die Entscheidung hierfür fiel erst nicht leicht, da das Angebot jener Bibliotheken die sich Drag & Drop verschrieben haben, nicht besonders klein ist. Aber wo wir gerade von klein reden, ist das bereits der wichtigste Punkt der Sortable.js von anderen abhebt. Weil sie nur das nötigste an Funktionalität abdeckt und keine fancy Animationen nutzt die nicht nur Leistung fressen sondern auch Dateigröße ist diese Bibliothek mit 25kB (minimized) eines der Leichtgewichte unter ihren Vertretern. Außerdem existiert keine Abhängigkeit zu jQueryUI, das alleine hat bereits überzeugt.

Nun aber zum eigentlichen Thema. Während Sortable.js wunderbar mit einfachen Listen arbeiten kann, wird es etwas anspruchsvoller wenn es um verschachtelte Listen geht. Glücklicherweise wurde in diesem Segment in den letzen Wochen einiges getan und die Unterstützung erheblich verbessert. Dennoch gibt es etwas das immer noch existiert und mir einige ruhelose Nächte bereitet hat. Gut, so schlimm war es nun auch wieder nicht, dennoch, es könnte ja einigen genauso wie mir nicht sofort wie Schuppen von den Augen fallen.

Aber erst einmal die Demo die das Problem darstellt. Versucht einmal alles aus der roten Liste zu entfernen und dann wieder Elemente aus der blauen hineinzuschieben. Demo

Klappt nicht so ganz? Tja, das liegt daran, dass die rote Liste zu klein ist sobald keine Elemente mehr enthalten sind. Der findige Leser denkt jetzt eventuell daran der Liste eine Mindesthöhe zu geben. Gar nicht so falsch. Demo

Klappt dennoch nicht? Hehe, willkommen im Club. Ein Blick in die README.md von Sortable.js und man findet emptyInsertThreshold. Leider führt der Name dieser Option eher in die Irre, denn die Lösung ist sie nicht. Euer Blick sollte eher auf invertSwap fallen. Demo

Warum das nun funktioniert? Arr, das geht etwas über das Ziel des Beitrags hinaus. Ich kann euch aber folgendes ans Herz legen.

Johannes Meyer
Johannes Meyer
Developer

Johannes ist seit 2011 bei uns und hilft bei der Entwicklung zukünftiger Knüller (Icinga2, Icinga Web 2, ...) aus dem Hause NETWAYS.

Modern C++ programming: Coroutines with Boost

(c) https://xkcd.com/303/

We’re rewriting our network stack in Icinga 2.11 in order to to eliminate bugs with timeouts, connection problems, improve the overall performance. Last but not least, we want to use modern library code instead of many thousands of lines of custom written code. More details can be found in this GitHub issue.

From a developer’s point of view, we’ve evaluated different libraries and frameworks before deciding on a possible solution. Alex created several PoCs and already did a deep-dive into several Boost libraries and modern application programming. This really is a challenge for me, keeping up with the new standards and possibilities. Always learning, always improving, so I had a read on the weekend in “Boost C++ Application Development Cookbook – Second Edition“.

One of things which are quite resource consuming in Icinga 2 Core is multi threading with locks, waits and context switching. The more threads you spawn and manage, the more work needs to be done in the Kernel, especially on (embedded) hardware with a single CPU core. Jean already shared insights how Go solves this with Goroutines, now I am looking into Coroutines in C++.

 

Coroutine – what’s that?

Typically, a function in a thread runs, waits for locks, and later returns, freeing the locked resource. What if such a function could be suspended at certain points, and continue once there’s resources available again? The benefit would also be that wait times for locks are reduced.

Boost Coroutine as library provides this functionality. Whenever a function is suspended, its frame is put onto the stack. At a later point, it is then resumed. In the background, the Kernel is not needed for context switching as only stack pointers are stored. This is done with Boost’s Context library which uses hardware registers, and is not portable. Some architectures don’t support it yet (like Sparc).

Boost.Context is a foundational library that provides a sort of cooperative multitasking on a single thread. By providing an abstraction of the current execution state in the current thread, including the stack (with local variables) and stack pointer, all registers and CPU flags, and the instruction pointer, a execution context represents a specific point in the application’s execution path. This is useful for building higher-level abstractions, like coroutinescooperative threads (userland threads) or an equivalent to C# keyword yield in C++.

callcc()/continuation provides the means to suspend the current execution path and to transfer execution control, thereby permitting another context to run on the current thread. This state full transfer mechanism enables a context to suspend execution from within nested functions and, later, to resume from where it was suspended. While the execution path represented by a continuation only runs on a single thread, it can be migrated to another thread at any given time.

context switch between threads requires system calls (involving the OS kernel), which can cost more than thousand CPU cycles on x86 CPUs. By contrast, transferring control vias callcc()/continuation requires only few CPU cycles because it does not involve system calls as it is done within a single thread.

TL;DR – in the way we write our code, we can suspend function calls and free resources for other functions requiring it, without typical thread context switches enforced by the Kernel. A more deep-dive into Coroutines, await and concurrency can be found in this presentation and this blog post.

 

A simple Example

$ vim coroutine.cpp

#include <boost/coroutine/all.hpp>
#include <iostream>

using namespace boost::coroutines;

void coro(coroutine::push_type &yield)
{
        std::cout << "[coro]: Helloooooooooo" << std::endl;
        /* Suspend here, wait for resume. */
        yield();
        std::cout << "[coro]: Just awesome, this coroutine " << std::endl;
}

int main()
{
        coroutine::pull_type resume{coro};
        /* coro is called once, and returns here. */

        std::cout << "[main]: ....... " << std::endl; //flush here

        /* Now resume the coro. */
        resume();

        std::cout << "[main]: here at NETWAYS! :)" << std::endl;
}

 

Build it

On macOS, you can install Boost like this, Linux and Windows require some more effort listed in the Icinga development docs). You’ll also need CMake and g++/clang as build tool.

brew install ccache boost cmake 

Add the following CMakeLists.txt file into the same directory:

$ vim CMakeLists.txt

cmake_minimum_required(VERSION 2.8.8)
set(BOOST_MIN_VERSION "1.66.0")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")

find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS context coroutine date_time thread system program_options regex REQUIRED)

# Boost.Coroutine2 (the successor of Boost.Coroutine)
# (1) doesn't even exist in old Boost versions and
# (2) isn't supported by ASIO, yet.
add_definitions(-DBOOST_COROUTINES_NO_DEPRECATION_WARNING)

link_directories(${Boost_LIBRARY_DIRS})
include_directories(${Boost_INCLUDE_DIRS})

set(base_DEPS ${CMAKE_DL_LIBS} ${Boost_LIBRARIES})

set(base_SOURCES
  coroutine.cpp
)

add_executable(coroutine
        ${base_SOURCES}
)

target_link_libraries(coroutine ${base_DEPS})

set_target_properties(
        coroutine PROPERTIES
        FOLDER Bin
        OUTPUT_NAME boost-coroutine
)

Next, run CMake to check for the requirements and invoke make to build the project afters.

cmake .
make

 

Run and understand the program

$ ./boost-coroutine
[coro]: Helloooooooooo
[main]: .......
[coro]: Just awesome, this coroutine
[main]: here at NETWAYS! :)

Now, what exactly happened here? The Boost coroutine library allows us to specify the “push_type” where this functions should be suspended, after reaching this point, a subsequent call to “yield()” is required to resume this function.

void coro(coroutine::push_type &yield)

Up until “yield()”, the function logs the first line to stdout.

The first call happens inside the “main()” function, by specifying the pull_type and directly calling the function as coroutine. The pull_type called “resume()” (free form naming!) must then be explicitly invoked in order to resume the coroutine.

coroutine::pull_type resume{coro};

After the first line is logged from the coroutine, it stops before “yield()”. The main function logs the second line.

[coro]: Helloooooooooo
[main]: .......

Now comes the fun part – let’s resume the coroutine. It doesn’t start again, but the function’s progress is stored as stack pointer, targeting “yield()”. Exactly this resume function is called with “resume()”.

        /* Now resume the coro. */
        resume();

That being said, there’s more to log inside the coroutine.

[coro]: Just awesome, this coroutine

After that, it reaches the end and returns to the main function. That one logs the last line and terminates.

[main]: here at NETWAYS! :)

Without a coroutine, such synchronisation between functions and threads would need waits, condition variables and lock guards.

 

Icinga and Coroutines

With Boost ASIO, the spawn() method wraps coroutines on a higher level and hides the strand required. This is used in the current code and binds a function into its scope. We’re using lambda functions available with C++11 in most locations.

The following example implements the server side of our API waiting for new connections. An endless loop listens for incoming connections with “server->async_accept()”.

Then comes the tricky part:

  • 2.9 and before spawned a thread for each connection. Lots of threads, context switches and memory leaks with stalled connections.
  • 2.10 implemented a thread pool, managing the resources. Handling the client including asynchronous TLS handshakes are slower, and still many context switches ahead between multiple connections until everything stalls.
  • 2.11 spawns a coroutine which handles the client connection. The yield_context is required to suspend/resume the function inside.

 

void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const std::shared_ptr& server, const std::shared_ptr& sslContext)
{
	namespace asio = boost::asio;

	auto& io (server->get_io_service());

	for (;;) {
		try {
			auto sslConn (std::make_shared(io, *sslContext));

			server->async_accept(sslConn->lowest_layer(), yc);

			asio::spawn(io, [this, sslConn](asio::yield_context yc) { NewClientHandler(yc, sslConn, String(), RoleServer); });
		} catch (const std::exception& ex) {
			Log(LogCritical, "ApiListener")
				<< "Cannot accept new connection: " << DiagnosticInformation(ex, false);
		}
	}
}

The client handling is done in “NewClientHandlerInternal()” which follows this flow:

  • Asynchronous TLS handshake using the yield context (Boost does context switches for us), Boost ASIO internally suspends functions.
    • TLS Shutdown if needed (again, yield_context handled by Boost ASIO)
  • JSON-RPC client
    • Send hello message (and use the context for coroutines)

And again, this is the IOBoundWork done here. For the more CPU hungry tasks, we’re using a different CpuBoundWork pool which again spawns another coroutine. For JSON-RPC clients this mainly affects syncing runtime objects, config files and the replay logs.

Generally speaking, we’ve replaced our custom thread pool and message queues for IO handling with the power of Boost ASIO, Coroutines and Context thus far.

 

What’s next?

After finalizing the implementation, testing and benchmarks are on the schedule – snapshot packages are already available for you at packages.icinga.com. Coroutines will certainly help embedded devices with low CPU power to run even faster with many network connections.

Boost ASIO is not yet compatible with Coroutine2. Once it is, the next shift in modernizing our code is planned. Up until then, there are more Boost features available with the move from 1.53 to 1.66. Our developers are hard at work with implementing bug fixes, features and learning all the good things.

There’s many cool things under the hood with Icinga 2 Core. If you want to learn more and become a future maintainer, join our adventure! 🙂

Michael Friedrich
Michael Friedrich
Senior Developer

Michael ist seit vielen Jahren Icinga-Entwickler und hat sich Ende 2012 in das Abenteuer NETWAYS gewagt. Ein Umzug von Wien nach Nürnberg mit der Vorliebe, österreichische Köstlichkeiten zu importieren - so mancher Kollege verzweifelt an den süchtig machenden Dragee-Keksi und der Linzer Torte. Oder schlicht am österreichischen Dialekt der gerne mit Thomas im Büro intensiviert wird ("Jo eh."). Wenn sich Michael mal nicht in der Community helfend meldet, arbeitet er am nächsten LEGO-Projekt oder geniesst...