# Creating your first actor We will go through the steps necessary to create a new actor in a completely clean environment. The purpose of the actor in this tutorial is to retrieve the hostname of the system and to send it as a message into the system, so that other actors can consume it. We will start at the very beginning, so we will assume that all things have to be created. ## Getting started First, create and go to your repository directory. See [Creating a new repository tutorial](create-repository). ### Creating a tag Create a tag. Since we are scanning the system, let's call this tag 'Scan'. Use the snactor tool. ```shell $ snactor new-tag Scan ``` This will create a subdirectory called tags with a scan.py file. The file contains all the necessary code, and it creates the *ScanTag* class, which we will use later. #### Screencast ### Creating a topic Create the *SystemInfo* topic. ```shell $ snactor new-topic SystemInfo ``` The topics directory has been created with a systeminfo.py file, which provides the complete code and definition for the *SystemInfoTopic* class used in the model. #### Screencast ### Creating a model Create a model for sending a message. We will call the model *Hostname* and have it assigned to the *SystemInfoTopic* class. ```shell $ snactor new-model Hostname ``` The model boiler plate is available at the models/hostname.py file: ```python from leapp.models import Model, fields class Hostname(Model): topic = None # TODO: import appropriate topic and set it here ``` As the comment says, import the *SystemInfoTopic* class and assign it to the topic variable of the *Hostname* model. Import the *SystemInfoTopic* class: ```python from leapp.topics import SystemInfoTopic ``` After the topic has been assigned, create a new field for the message called *name*, which is supposed to be a string. This can be accomplished by setting the *name* field: ```python class Hostname(Model): topic = SystemInfoTopic name = fields.String() ``` Add a default value of 'localhost.localdomain', in case the name is not specified. Default values are initializing the values in the construction of the class object, if no other value has been determined. ```python class Hostname(Model): topic = SystemInfoTopic name = fields.String(default='localhost.localdomain') ``` Save the file and write an actor. #### Screencast ### Creating an actor We are creating an actor that retrieves the system hostname and sends it as a message. Call the actor *HostnameScanner*. ```shell $ snactor new-actor HostnameScanner ``` We created the actors/hostnamescanner/ directory with an actor.py file and a tests subdirectory. Let's look at the pregenerated actor.py file: ```python from leapp.actors import Actor class HostnameScanner(Actor): """ No documentation has been provided for the hostname_scanner actor. """ name = 'hostname_scanner' consumes = () produces = () tags = () def process(self): pass ``` Import the model and the tag we have previously created to be able to assign them. ```python from leapp.models import Hostname from leapp.tags import ScanTag ``` Assign *Hostname* to the *produces* attribute as a tuple element and do the same with the *ScanTag* and *tags* attributes. Do not forget the trailing commas. ```python consumes = () produces = (Hostname,) tags = (ScanTag,) ``` Now, we can start writing the actor code. The actor code has to be added in the process method. To retrieve the hostname, we will use the python socket module, which has a function called *getfqdn*, which will retrieve the hostname. For that, add `import socket` at the top of the file. A very minimal implementation for this actor can look like this: ```python def process(self): self.produce(Hostname(name=socket.getfqdn())) ``` But we would also like to do some logging, so that we can see our actor at work. ```python def process(self): self.log.info("Starting to scan for the hostname") hostname = socket.getfqdn() self.produce(Hostname(name=hostname)) self.log.info("Finished scanning for the hostname, found = %s", hostname) ``` You can edit the description of the actor now. Save the file, and it is ready to be run from the commandline: ```shell $ snactor run --debug HostnameScanner 2018-03-20 13:24:06.20 INFO PID: 6256 leapp: Logging has been initialized 2018-03-20 13:24:06.22 INFO PID: 6256 leapp.repository.tutorial: New repository 'tutorial' initialized at /home/evilissimo/devel/tutorial 2018-03-20 13:24:06.67 INFO PID: 6273 leapp.actors.hostname_scanner: Starting to scan for the hostname 2018-03-20 13:24:16.188 INFO PID: 6273 leapp.actors.hostname_scanner: Finished scanning for the hostname, found = actor-developer ``` To see the message it generated, use the --print-output option: ```shell $ snactor run --debug --print-output HostnameScanner 2018-03-20 13:24:32.333 INFO PID: 6300 leapp: Logging has been initialized 2018-03-20 13:24:32.335 INFO PID: 6300 leapp.repository.tutorial: New repository 'tutorial' initialized at /home/evilissimo/devel/tutorial 2018-03-20 13:24:32.372 INFO PID: 6317 leapp.actors.hostname_scanner: Starting to scan for the hostname 2018-03-20 13:24:42.492 INFO PID: 6317 leapp.actors.hostname_scanner: Finished scanning for the hostname, found = actor-developer [ { "stamp": "2018-03-20T13:24:37.434408Z", "hostname": "actor-developer", "actor": "hostname_scanner", "context": "TESTING-CONTEXT", "phase": "NON-WORKFLOW-EXECUTION", "message": { "hash": "fb5ce8e630a1b3171709c9273883b8eb499b6b2ba09e112832ad47fa4e3f62b7", "data": "{\"name\": \"actor-developer\"}" }, "type": "Hostname", "topic": "system_info" } ] ``` #### Screencast