# Extensions for noobs

**URL:** <https://forum.genieacs.com/t/extensions-for-noobs/3092>\
**Category:** Uncategorized\
**Created:** [October 18, 2022, 9:25am UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092 "2022-10-18T09:25:51Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![egor.gr](https://avatars.discourse-cdn.com/v4/letter/e/7ea924/32.png) [@egor.gr](https://forum.genieacs.com/u/egor.gr)\
**Post date:** [October 18, 2022, 9:25am UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/1 "2022-10-18T09:25:51Z")

</div>

Hello.  
I am new to genie, and this caused some problems to me.  
What am i trying to understand is how to work with extensions.  
I am trying simple scenario:set variable from extension script and then print this var in the log.  
I made a new preset with bootstrap event and made a new provision.  
At first stage i made a simple new provision with simple script:  
`log('Extension test output: ');`  
And in the logs i see that all works fine:  
`2022-10-18T10:58:24.557Z [INFO] ::ffff:100.127.33.170 00259E-HG8247W5-48575443B8A8B1A0: Script: Extension test output:`

After this i made a simple js script,placed in ext folder and checked that script belongs to genie user:

```auto
cat myext.js
function myfunc() {
            return("Hello");
                    }
exports.myfunc = myfunc;

```

And modified my test provision:

```auto
let myvar=ext("myext","myfunc");
log('Extension test output: '+myvar);

```

But after these steps i get in log  
`...faultCode="timeout" faultMessage="Extension timed out"`

I just cant understand what is wrong. Extension script is very simple.  
Can somebody explain what is wrong in my scenario?

---

<div class="post-metadata">

**Author:** ![rudymartin](https://avatars.discourse-cdn.com/v4/letter/r/919ad9/32.png) [@rudymartin](https://forum.genieacs.com/u/rudymartin)\
**Post date:** [October 18, 2022, 1:31pm UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/2 "2022-10-18T13:31:31Z")

</div>

have you tried the basic example provided in the documentation?

[https://docs.genieacs.com/en/latest/extensions.html](https://docs.genieacs.com/en/latest/extensions.html)

it was the first one I ever tested and gave me the basic understanding on how extensions works.

your example looks good to me. While checking my ext permissions I have found it’s owned by root but Others readable. I have to guess permissions are not really an issue, but it’s worth checking.

---

<div class="post-metadata">

**Author:** ![rudymartin](https://avatars.discourse-cdn.com/v4/letter/r/919ad9/32.png) [@rudymartin](https://forum.genieacs.com/u/rudymartin)\
**Post date:** [October 18, 2022, 1:33pm UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/3 "2022-10-18T13:33:14Z")

</div>

also don’t forget about checking the logs at `journalctrl -f` (Debian)

---

<div class="post-metadata">

**Author:** ![akcoder](https://yyz1.discourse-cdn.com/flex035/user_avatar/forum.genieacs.com/akcoder/32/11_2.png) [@akcoder](https://forum.genieacs.com/u/akcoder)\
**Post date:** [October 18, 2022, 4:49pm UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/4 "2022-10-18T16:49:47Z")

</div>

> [@rudymartin](#):
>
> your example looks good to me

It does not look good to me. Its missing the second param which is the callback that needs to be called when all the information is ready to return to the provision script. This is why @egor.gr is getting the timeout message.

---

<div class="post-metadata">

**Author:** ![egor.gr](https://avatars.discourse-cdn.com/v4/letter/e/7ea924/32.png) [@egor.gr](https://forum.genieacs.com/u/egor.gr)\
**Post date:** [October 19, 2022, 7:54am UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/5 "2022-10-19T07:54:02Z")

</div>

The return procedure is not acceptable in extension script?

---

<div class="post-metadata">

**Author:** ![egor.gr](https://avatars.discourse-cdn.com/v4/letter/e/7ea924/32.png) [@egor.gr](https://forum.genieacs.com/u/egor.gr)\
**Post date:** [October 19, 2022, 9:40am UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/6 "2022-10-19T09:40:28Z")

</div>

I have a little success with running extension.  
But now there is a problem with reading local file.  
I am trying to search if some text file contains serial number and return the result.  
The new script is:

```auto
function checkonu(args, callback) {
let sn = args[0];
let onures="";
var fs = require("fs"), searchString = "ZTEEQLYN5C00002";
fs.readFile("/opt/genieacs/ext/onus.txt", function(err, content) {
    if (err) throw err;
             onures=content.indexOf(searchString)>-1 ? "has string" : "does not have string";
                      });
callback(null, onures);
}
exports.checkonu = checkonu;

```

File /opt/genieacs/ext/onus.txt belongs to

`-rw-r--r-- 1 genieacs genieacs 16 Oct 19 13:08 onus.txt`  
The problem is that its like script doesnt search string in file.  
However if i harcode variable onures to some value i see this value in the logs.  
For example if after line  
`onures=content.indexOf(searchString)>-1 ? "has string" : "does not have string";`  
i add  
`onures="SomeTestValue"`  
I see in log(provision script is set to log onures variable) “SomeTestValue”  
But if script remains as it is, in the logs i see that onures remains empty in the logs.  
Am i missing some additional permissions to onus.txt or extensions from geanie cannot read files on filesystem?

---

<div class="post-metadata">

**Author:** ![egor.gr](https://avatars.discourse-cdn.com/v4/letter/e/7ea924/32.png) [@egor.gr](https://forum.genieacs.com/u/egor.gr)\
**Post date:** [October 19, 2022, 11:27am UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/7 "2022-10-19T11:27:00Z")

</div>

Sorry  
The problem was in cycles and conditions.  
In other words callback was called out of conditions blocks  
Working variant of script is

```auto
function checkonu(args, callback) {
let sn = args[0];
let onures="11";
const fs = require('fs');

fs.readFile('onus.txt', 'utf8', (err, data) => {
  if (err) {
        let onures=err;
        callback(null,onures);
                  return;
                              }
                                            console.log(data);
                                            onures=data;
                                            console.log(onures);
                                            callback(null,onures);
                                                          });
}
exports.checkonu = checkonu;

```

---

<div class="post-metadata">

**Author:** ![akcoder](https://yyz1.discourse-cdn.com/flex035/user_avatar/forum.genieacs.com/akcoder/32/11_2.png) [@akcoder](https://forum.genieacs.com/u/akcoder)\
**Post date:** [October 19, 2022, 4:08pm UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/8 "2022-10-19T16:08:13Z")

</div>

> [@egor.gr](#):
>
> The return procedure is not acceptable in extension script?

No, you have to call the callback when done.

---

<div class="post-metadata">

**Author:** ![akcoder](https://yyz1.discourse-cdn.com/flex035/user_avatar/forum.genieacs.com/akcoder/32/11_2.png) [@akcoder](https://forum.genieacs.com/u/akcoder)\
**Post date:** [October 19, 2022, 4:24pm UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/9 "2022-10-19T16:24:25Z")

</div>

A couple of things, your extension script file should end in .js, not .txt. Your callback in the if err condition is wrong. The error code/value/data is the first param to the callback. Here is a cleaned up and corrected version of your latest script:

```auto
function checkonu(args, callback) {
    let sn = args[0];
    let onures = "11";
    const fs = require('fs');

    fs.readFile('onus.txt', 'utf8', (err, data) => {
        if (err) {
            callback(err);

            return;
        }

        console.log(data);

        callback(null, data);
    });
}

exports.checkonu = checkonu;

```

---

<div class="post-metadata">

**Author:** ![lgorordo](https://avatars.discourse-cdn.com/v4/letter/l/71c47a/32.png) [@lgorordo](https://forum.genieacs.com/u/lgorordo)\
**Post date:** [February 20, 2025, 8:43pm UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/10 "2025-02-20T20:43:02Z")

</div>

Question, on the provisioning script side, how can I control the status of the extension script, by means of a try, catch ? It returns ‘Symbol()’ .  
Instead, if I run it without try,catch it works correctly but I have no control of the exception.

---

<div class="post-metadata">

**Author:** ![akcoder](https://yyz1.discourse-cdn.com/flex035/user_avatar/forum.genieacs.com/akcoder/32/11_2.png) [@akcoder](https://forum.genieacs.com/u/akcoder)\
**Post date:** [February 20, 2025, 8:51pm UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/11 "2025-02-20T20:51:32Z")

</div>

Paste the code of your extension and your provision script. Please use code blocks (three backticks ``` on a new line, followed by your code, followed by ``` on a new line again).

Example:

```  
declare(‘InternetGatewayDevice.SomeParam’…);  
```

---

<div class="post-metadata">

**Author:** ![lgorordo](https://avatars.discourse-cdn.com/v4/letter/l/71c47a/32.png) [@lgorordo](https://forum.genieacs.com/u/lgorordo)\
**Post date:** [February 20, 2025, 9:00pm UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/12 "2025-02-20T21:00:01Z")

</div>

Thank you for your prompt reply, I attach the extensions file, with the basic functionalities. There is a function that to not complicate the understanding we remove the logic and returns a test value.

I also attach the associated provisioning code where is called

extension:

```auto
const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');

// Cargar el archivo .proto y cargar el paquete gRPC
const packageDefinition = protoLoader.loadSync('./utils/poller.proto');
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
const AcsService = protoDescriptor.AcsService;

// Dirección del servidor gRPC
const serverAddress = '10.100.10.227:9090';

// Crear un cliente gRPC
const client = new AcsService(serverAddress, grpc.credentials.createInsecure());

function processResponse(response) {
    //DUMMY FUNCTION
    response = "test"
    return response;
}

function makeRpcCall(data) {
    return new Promise((resolve, reject) => {
        const request = {
            sn:data.sn,
            model:data.model,
            hwver:data.hwver,
            swver:data.swver,
            fwver:data.fwver,
            vendor:data.vendor,
            deviceid:data.deviceid,
        };

        client.getResources(request, (error, response) => {
            if (error) {
                console.error('Error:', error);
                reject(error);
                return;
            }

            if(response.status === 1 ) {
                console.error('FAILURE:', error_description);
                reject(error_message);
                return;
            }
            
            let objectsList = [];

            response.declareObjects.forEach(declareObject => {
                dataProcessed = processResponse(declareObject);
                objectsList.push(dataProcessed);
            });
            resolve(objectsList);
        });
    });
}

function getDataInventory(args, callback) {
    let params = JSON.parse(JSON.parse(args[0]));
    if (params.sn != null && params.sn !== undefined) {
        makeRpcCall(params)
            .then(result => {
                callback(null, result);
            })
            .catch(error => {
                console.error('Ocurrió un error:', error);
                callback(error);
            });
    } else {
        callback(new Error('El parámetro "serial" no está definido'));
    }
}

exports.getInventory = getDataInventory;

```

provisioning , segment code:

```auto
let data = []
  let operationResult = true
  try{
    data = ext('inventory_server', 'getInventory', JSON.stringify(DeviceInfoExtended));
  } catch {
    log("Problems obtaining inventory information associated with the device")
    operationResult = false
  }

```

---

<div class="post-metadata">

**Author:** ![akcoder](https://yyz1.discourse-cdn.com/flex035/user_avatar/forum.genieacs.com/akcoder/32/11_2.png) [@akcoder](https://forum.genieacs.com/u/akcoder)\
**Post date:** [February 20, 2025, 9:28pm UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/13 "2025-02-20T21:28:28Z")

</div>

Try this, but be warned its just a wild assed guess.

```auto
        makeRpcCall(params)
            .then(result => callback(null, result))
            .catch(error => {
                console.error('Ocurrió un error:', error);

                return callback(error);
            });

```

---

<div class="post-metadata">

**Author:** ![lgorordo](https://avatars.discourse-cdn.com/v4/letter/l/71c47a/32.png) [@lgorordo](https://forum.genieacs.com/u/lgorordo)\
**Post date:** [February 21, 2025, 11:07am UTC](https://forum.genieacs.com/t/extensions-for-noobs/3092/14 "2025-02-21T11:07:47Z")

</div>

> [@akcoder](#):
>
> ```auto
> makeRpcCall(params)
> .then(result => callback(null, result))
> .catch(error => {
> console.error('Ocurrió un error:', error);
> 
> return callback(error);
> });
> 
> ```

Hello, I’m sorry, maybe I’m not understanding you, do you suggest me to modify the function of my extension file? what changes do you suggest me ?

```auto
function getDataInventory(args, callback) {
    let params = JSON.parse(JSON.parse(args[0]));
    if (params.sn != null && params.sn !== undefined) {
        makeRpcCall(params)
            .then(result => {
                callback(null, result);
            })
            .catch(error => {
                console.error(‘An error occurred:’, error);
                callback(error);
            });
    } else {
        callback(new Error(‘The parameter “serial” is not defined’));
    }
}

```
