\chapter{Ontwerp}

In dit ontwerp zal een Ansible inventory plugin worden beschreven waarmee TOPdesk Asset Management direct als inventory bron kan worden gebruikt. Op deze manier hoeft geen informatie handmatig gekopieerd te worden vanuit Asset Management naar een inventory bestand maar kan de gewenste apparatuur worden opgegeven en zal de plugin alle benodigde data ophalen de apparatuur waarna deze gebruikt kan worden in playbooks en ad hoc commando's.

\begin{figure}[h]
    \centering
    \includegraphics[scale=0.7]{figures/highlevel.pdf}
    \caption{Top level design}
\end{figure}


\section{Ontwerpmogelijkheden}

In dit hoofdstuk worden verschillende ontwerpkeuzes en geassocieerde eigenschappen gedocumenteerd die zijn gemaakt. 

\subsection{Integratie met Ansible}

Het doel van het systeem is om een inventory genereren voor gebruik met Ansible. Er zijn verschillende mogelijkheden om dit te bereiken, deze zullen in dit hoofdstuk beschreven worden.

\subsubsection{Browser extensie}

Een van de mogelijkheden is het ontwikkelen van een browserextensie die actief wordt op de TOPdesk Asset Management Web Interface. De gebruiker kan dan de normale interface gebruiken van Asset Management om filters toe te passen en apparaten te selecteren die in het inventory opgenomen dienen te worden. Vervolgens biedt de extensie een functionaliteit om de huidige selectie te exporteren naar een Ansible Inventory bestand.

Voordelen:

\begin{itemize}
    \item Het inventory kan worden samengesteld door gebruik te maken van een grafische interface die ook al bekend is binnen het team. (Usability)
\end{itemize}


\subsubsection{Ansible Inventory Plugin}

Ansible kan op verschillende manier worden uitgebreid waaronder door het maken van een 'Inventory Plugin'. Dit soort plugins kunnen worden geschreven in Python en worden toegevoegd aan Ansible om te integreren met een andere applicaties voor het ophalen van een inventory.

Instellingen van een inventory plugin worden in een configuratiebestand gezet met YAML opmaak. In dit configuratiebestand zal de gebruiker dus alle filters moeten definiëren die moeten worden gebruikt om de gewenste apparaten op te halen.

Voordelen:

\begin{itemize}
    \item Deze manier van een inventory genereren is zeer geschikt voor gebruik in combinatie met AWX omdat hier geen handmatige acties vereist zijn behalve het opstellen van de initiële configuratie. Daarna kan AWX met dezelfde configuratie het inventory steeds vernieuwen.
\end{itemize}


\subsubsection{Dynamisch inventory script}

Ansible biedt ook de mogelijkheid om de output van een extern script te kunnen gebruiken als inventory indien deze de correcte structuur heeft. Het externe script wordt uitgevoerd door Ansible en de output van dit script moet in JSON geformatteerd zijn. Daarnaast moet het script verschillende argumenten accepteren \cite{ansible_script_inventory_requirements}.

Een van de voordelen van een inventory script is dat deze in elke taal kan worden geïmplementeerd, zolang de output maar voldoet aan de requirements van Ansible en kan worden uitgevoerd.

Er wordt echter aangeraden om een Inventory Plugin te gebruiken in plaats van inventory scripts \cite{ansible_script_inventory_statement}.


\subsection{Koppeling met TOPdesk Asset Management}

Het inventory zal opgebouwd moeten worden op basis van gegevens afkomstig uit TOPdesk Asset Management, dit is namelijk het systeem waarin alle apparatuur wordt bijgehouden. Er zal dus een direct of indirecte koppeling moeten komen met dit systeem. Hier bestaan de volgende mogelijkheden:


\subsubsection{TOPdesk Asset Management REST API}

Asset Management stelt een REST API beschikbaar waarmee de apparatuur kan worden opgehaald, aangemaakt, gewijzigd of verwijderd kan worden inclusief alle informatie die hieraan verbonden is. De API maakt gebruik van een JSON indeling waardoor het antwoord gemakkelijk uitgelezen kan worden.

Voordelen:

\begin{itemize}
    \item JSON is gemakkelijk uit te lezen door de meeste programmeertalen. Dit kan complexiteit van de oplossing verkleinen
    \item REST API's zijn zeer goed ondersteund door de meeste programmeertalen en hier zijn veel tools voor beschikbaar. Dit maakt de oplossing gemakkelijker te onderhouden
\end{itemize}

Nadelen:

\begin{itemize}
    \item De meeste velden van een apparaat bevatten unieke ids in plaats van leesbare text. Dit is bijvoorbeeld het geval als men een dropdown veld met bepaalde waardes toevoegt, de API geeft het unieke id in plaats van de text waarde van de dropdown. Dit verhoogt de complexiteit van de oplossing
    \item De hoeveelheid resultaten is niet te wijzigen en staat vast op 50. Dit zorgt ervoor dat wanneer alle resultaten benodigd zijn meerdere verzoeken moeten worden gemaakt naar de server om alle resultaten op te halen (wanneer het aantal resultaten over de 50 bedraagt). Dit verhoogt de complexiteit van de oplossing
\end{itemize}


\subsubsection{Excel export}

In Asset Management kan ook een Excel document worden geëxporteerd met alle (geselecteerde) assets. Dit excel document zou eventueel verwerkt kunnen worden tot een Ansible inventory.

Voordelen:

\begin{itemize}
    \item De gebruiker kan filters toepassen in de bekende TOPdesk Asset Management web interface en daarna de assets exporteren. Dit maakt het gemakkelijker voor de gebruiker om de gewenste apparatuur te selecteren.
\end{itemize}

Nadelen:

\begin{itemize}
    \item Een ouder geëxporteerd Excel document kan potentieel niet meer de actuele apparatuur of gegevens bevatten. Dit maakt het minder gemakkelijk om te gebruiken.
\end{itemize}




\section{Ontwerpkeuzes}

Dit hoofdstuk ligt de gemaakte keuzes toe.

\subsection{Ansible Inventory Plugin}

Er is gekozen om het inventory te genereren door een Ansible Inventory Plugin in plaats van dynamisch inventory of door andere externe tool. Deze keuze is voor de volgende redenen gemaakt:

\begin{enumerate}
    \item In een Ansible Plugin of module kan gebruik worden gemaakt van Ansibles Python API. Deze API bevat functies die vaker gebruikt worden bij het genereren van een inventory en/of integraties met Ansible. Hierdoor hoeft minder functionaliteit zelf ontworpen, geïmplementeerd en onderhouden te worden en verlaagt de complexiteit van de oplossing. Als resultaat verhoogt dit de \textit{maintainability} van de oplossing.
    \item Omdat een Ansible Inventory Plugin een officiële manier is om de functionaliteit van Ansible uit te breiden wordt dit ook ondersteund in Ansible AWX, een automatiseringsplatform die gebruik maakt van Ansible. \textit{compatibility, usability, scalability}.
\end{enumerate}


\subsection{TOPdesk Asset Management REST API}

Als bron voor de benodigde informatie over de apparatuur die in productieomgevingen aanwezig is wordt gebruik gemaakt van de REST API van het TOPdesk Asset Management systeem. Hierdoor garandeert de plugin dat de opgehaalde informatie altijd actueel is. Een aantal eigenschappen van deze API:

\begin{itemize}
    \item De API werkt met de JSON indeling.
    \item Er kan een query worden opgebouwd met een 'FIQL' string \cite{topdesk_api_tutorial}. Deze bevat alle criteria die nodig zijn om de gewenste assets te selecteren (gescheiden met een komma).
    \item De API reageert met maximaal 50 resultaten. Indien er meer resultaten beschikbaar zijn reageert de API met status code 206 (not complete). De volgende pagina moet worden opgehaald door een query te maken waarbij de naam van de assets groter moeten zijn dan de laatst ontvangen asset (omdat de assets standaard zijn gesorteerd op naam). \cite{topdesk_asset_management_api}
\end{itemize}



\section{Minimaal benodigde gegevens}

In dit hoofdstuk wordt beschreven welke gegevens minimaal benodigd zijn om de inventory plugin effectief toe te kunnen passen in de praktijk. De gegevens kunnen binnen Ansible op verschillende manieren relevant zijn. Het gegeven kan noodzakelijk zijn om toegang te krijgen door Ansible tot het apparaat dat geconfigureerd dient te worden. Voorbeelden hiervan zijn het IP-adres of hostname waar het apparaat op bereikbaar is en eventuele authenticatie gegevens om toegang te verkrijgen tot het apparaat.

\begin{tabular}{l p{0.45\linewidth} l}
    \toprule
    Gegeven& Omschrijving& Bron\\
    \midrule
    TOPdesk URI& Het adres van de TOPdesk installatie \cite{topdesk_api_tutorial}.& Handmatig\\
    TOPdesk gebruikersnaam& Gebruikersnaam voor authenticatie doeleinden met TOPdesk \cite{topdesk_api_tutorial}.& Handmatig\\
    TOPdesk API Key& Een key voor authenticatie doeleinden met TOPdesk \cite{topdesk_api_tutorial}.& Handmatig\\ 
    Gebruikersnaam& Voor authenticatie doeleinden met het eindapparaat.& Handmatig\\
    Wachtwoord& Voor authenticatie doeleinden met het eindapparaat.& Handmatig\\
    IP-adres& Het IP-adres waar het eindapparaat mee te bereiken is.& Asset Management\\
    Hostnaam& De hostnaam van het apparaat zodat het duidelijk is welk apparaat het betreft voor de gebruiker.& Asset Management\\
    \bottomrule
\end{tabular}


\section{Configuratie interface}

Om een Ansible inventory plugin te gebruiken/configureren zal deze moeten worden gespecificeerd in het YAML inventory bestand door "plugin: <naam plugin>" hierin op te nemen. Vervolgens kan de plugin zelf configuratieopties definiëren die door de eindgebruiker kunnen worden gebruikt om de werking van de plugin te beïnvloeden.

In afbeelding \ref{fig:voorbeeld_aws_ec2_inventory} is een voorbeeld te zien van de manier waarop de inventory plugin voor AWS EC2 is te gebruiken. Deze plugin zorgt ervoor dat een inventory wordt opgebouwd op basis van de virtuele machines in een AWS subscription.

\begin{figure}[h]
    \begin{lstlisting}
        plugin: aws_ec2
        regions:
        - us-east-1
    \end{lstlisting}
    \caption{inventory.yaml AWS voorbeeld \cite{aws_ec2_inventory_documentatie}}
    \label{fig:voorbeeld_aws_ec2_inventory}
\end{figure}

\subsection{User Experience}

De benodigde instellingen voor het opbouwen van een inventory met daarin de gewenste apparatuur kan met name op twee verschillende manieren:

\begin{enumerate}
    \item \label{ue_criteria_gebasseerd} De plugin kan geconfigureerd worden met criteria waar een apparaat aan moet voldoen om in het inventory te worden opgenomen. Dus bijvoorbeeld van een bepaalde klant, locatie of type apparaat.
    \item \label{ue_naam_gebasseerd} De plugin zou ook geconfigureerd kunnen worden met de (unieke) namen van de apparaten die in het inventory opgenomen dienen te worden. Op deze manier kan de gebruiker in de web interface van Asset Management bepaalde filters configureren en vervolgens de namen van de apparaten kopiëren en in de configuratie plaatsen.
\end{enumerate}

Met name zijn de volgende verschillen relevant tussen deze mogelijkheden:

\begin{itemize}
    \item Punt \ref{ue_criteria_gebasseerd} is geschikter voor een zeer groot aantal apparaten. Dit komt omdat niet voor elk apparaat de naam in de configuratie gezet hoeft te worden.
    \item Punt \ref{ue_naam_gebasseerd} is geschikter voor een kleiner aantal apparaten. Dit komt doordat de gebruiker direct de namen kan opgeven van de apparaten en niet hoeft te zoeken naar alle filteropties die tot de gewenste selectie leveren.
    \item Punt \ref{ue_criteria_gebasseerd} zou de plugin aanzienlijk complexer maken omdat voor bijna elke eigenschap een filteroptie moet komen. Hierdoor zal de plugin lastiger te onderhouden zijn.
\end{itemize}

Op basis van deze eigenschappen is gekozen voor punt \ref{ue_naam_gebasseerd}. Hierdoor moet het zeer toegankelijk zijn vooral voor de dagelijkse werkzaamheden (wijzigingen op een grote hoeveelheid apparaten komen niet elke dag voor). Daarnaast kan dit naar aanleiding van de bevindingen nog aangepast worden naderhand.


\subsection{Configuratieopties}

De volgende configuratieopties moeten beschikbaar worden gesteld aan de eindgebruiker door de inventory plugin:

\begin{table}[h]
    \caption{Alle configuratie settings die beschikbaar moeten worden gesteld}
    \label{tbl:configuratie_settings}
    \begin{tabular}{l l l p{0.4\linewidth}}
        \toprule
        \textbf{Setting}& \textbf{Type}& \textbf{Required}& \textbf{Omschrijving}\\
        \midrule

        TOPdesk url&
        string&
        Ja&
        Het adres waarop de TOPdesk installatie is te bereiken\\

        TOPdesk gebruikersnaam&
        string&
        Ja&
        De gebruikersnaam van het account om te gebruiken met TOPdesk (moet rechten hebben voor Asset Management)\\

        TOPdesk API key&
        string&
        Ja&
        Een API key die is aangemaakt in TOPdesk \cite{topdesk_api_tutorial}\\

        Velden&
        list&
        Ja&
        Een lijst met velden die je wilt gebruiken in je playbook afkomstig van Asset Management\\

        Assets&
        list&
        Ja&
        Een lijst met de namen van de apparatuur die je in het inventory wilt opnemen\\

        ansiblehost&
        string&
        Ja&
        Het veld dat Ansible moet gebruiken om verbinding te maken met het eindapparaat, dus een IP-adres of hostnaam\\


        \bottomrule
        
    \end{tabular}
\end{table}

\pagebreak

\section{Technisch ontwerp}

In dit hoofdstuk wordt beschreven hoe de plugin zal werken vanuit een technisch aspect. In afbeelding \ref{fig:procestekening} is te zien welke stappen ondernomen zullen worden om uiteindelijk een bruikbaar inventory te kunnen genereren.

\begin{figure}[h]
    \label{fig:procestekening}
    \centering
    \includegraphics[scale=0.7]{figures/ontwerp.pdf}
    \caption{Proces van de plugin}
\end{figure}

\subsection{Valideer configuratie}

Om te kunnen functioneren moeten de configuratieopties voldoen aan enkele eisen, indien dat niet het geval is moet de gebruiker hierover worden ingelicht zodat het probleem verholpen kan worden, dit moet de gebruiksvriendelijkheid van de plugin verhogen.

Tabel \ref{tbl:conf_criteria} documenteert de criteria waar de configuratieopties aan moeten voldoen. Wanneer dat niet het geval is zal een foutmelding gegeven worden.

\begin{table}[h]
    \caption{Criteria aan configuratie}
    \label{tbl:conf_criteria}
    \centering
\begin{tabular}{l l l p{0.6\linewidth}}
    \toprule
    \textbf{Optie}& \textbf{Type}& \textbf{Verplicht}& \textbf{Criteria}\\
    \midrule
    URL&
    string&
    Ja&
    \begin{itemize}
        \item Moet naar een toegankelijke TOPdesk installatie wijzen. 
    \end{itemize}\\

    username&
    string&
    Ja&
    \\

    application$\_$key&
    string&
    Ja&
    \begin{itemize}
        \item Moet een application id bevatten geassocieerd met het opgegeven TOPdesk account \cite{topdesk_api_tutorial}.
    \end{itemize}\\

    fields&
    list&
    Ja&
    \begin{itemize}
        \item Bevat een lijst van de velden die moeten worden opgehaald van elk apparaat.
    \end{itemize}\\

    names&
    list&
    Ja&
    \begin{itemize}
        \item Bevat een lijst van de namen (string) van apparaten die in het inventory aanwezig moeten zijn.
    \end{itemize}\\

    ansible$\_$host&
    string&
    Ja&
    \begin{itemize}
        \item bevat de naam van het veld waar het apparaat mee bereikt kan worden. Dus een hostname of IP-adres.
    \end{itemize}\\



    \bottomrule
\end{tabular}
\end{table}


\subsection{Ophalen van Assets}

Om de apparatuur op te halen wordt de REST API van Asset Management gebruikt. De API maakt gebruikt van 'basic' HTTP Authenticatie, hiermee kan een client zich authenticeren met een gebruikersnaam en wachtwoord \cite{rfc7617}. Als wachtwoord wordt een 'application key' gebruikt in plaats van het wachtwoord van de gebruiker \cite{topdesk_api_tutorial}.

Voor elk apparaat die wordt opgegeven door de gebruiker zal een verzoek worden gestuurd om de actuele informatie van dit apparaat op te halen (inclusief alle velden die de gebruiker opgeeft). In tabel \ref{tbl:voorbeeld_request} is een voorbeeld te zien van hoe een request eruit kan zien. In appendix \ref{appendix:assetmgmt_api_response} is een voorbeeld te zien van de response van de server.

De response bevat twee soorten gegevens: de assets zelf en informatie over de velden die de assets bevatten. De assets en de velden die nog niet zijn opgeslagen worden bewaard.

\begin{table}[h!]
    \caption{Verzoek voor het ophalen van informatie over een asset}
    \label{tbl:voorbeeld_request}
\begin{tabular}{r l}
    \textbf{URI}&
    https://<kembit topdesk>/tas/api/assetmgmt/assets\\

    \textbf{Method}&
    GET\\

    \textbf{Authentication}&
    Basic: username + application key\\

    \textbf{Headers}&
    Accept: application/json\\

    \multirow{2}{*}{\textbf{Parameters}}&
    fields: \textit{<De namen van de gewenste velden gescheiden met komma>}\\

    &
    \$filter: 'name eq \textit{<naam van op te halen asset>}'\\    
\end{tabular}
\end{table}


\subsection{Ophalen van veldinformatie}

In de response van de Asset Management API in Appendix \ref{appendix:assetmgmt_api_response} is direct een probleem te zien, namelijk dat het 'status' veld geen tekstuele waarde bevat maar een uniek id. Dit unieke id is niet leesbaar en zal vervangen moeten worden met een tekstuele waarde.

Om dit te doen moet eerst de veldinformatie worden opgehaald waaruit afgeleid kan worden wat de tekstuele waarde is geassocieerd met elk mogelijk id. De response in Appendix \ref{appendix:assetmgmt_api_response} geeft onder de 'columns' key wat informatie over de velden, waaronder een link waarmee de mogelijkheden van het veld kunnen worden opgehaald. Deze veldinformatie is opgeslagen in de vorige stap (hoofdstuk).

Om alle mogelijke waardes van velden op te halen kan over de bewaarde veldinformatie worden geïtereerd waarbij de url wordt opgevraagd en de reactie hierop wordt opgeslagen. Nadat dit is gebeurd is alle data bekend om de ids om te zetten naar tekstuele waardes.


\subsection{Dataverwerking}

Op dit punt is veel data verzameld en zal deze samen moeten worden gebracht om een complete lijst van de apparatuur (inclusief alle tekstuele veldwaardes) te krijgen. De volgende informatie is opgehaald en beschikbaar:

\begin{itemize}
    \item Assets - De apparatuur (waarbij sommige waardes een id bevatten in plaats van leesbare tekst)
    \item Columns - Informatie over de velden van de apparatuur (inclusief een url waarmee de veldwaardes opgehaald kunnen worden)
    \item Veldwaardes - Per veld de waardes die dit veld kan bevatten (en de geassocieerde ids)
\end{itemize}

Nu kan in de lijst van assets alle ids worden vervangen met tesktwaardes door de ids op te zoeken in de opgehaalde veldwaardes geassocieerd met het gewenste veld.


\subsection{Inventory produceren}

Het uiteindelijke inventory kan nu worden doorgegeven middels de Ansible API zodat deze door de eindgebruiker kan worden benut.

Ansibles Python API biedt functies die gebruikt kunnen worden in de plugin om apparaten variabelen, en groepen toe te voegen aan het inventory. Voor elk appaaat wordt deze toegevoegd aan het inventory. Vervolgens wordt voor elk veld dat dit apparaat bevat de waarde en naam van dit veld toegevoegd als variabelen.