Page 3 of 4

Re: Communicating with Zabbix from REXX

PostPosted: Mon Mar 08, 2021 2:28 am
by enrico-sorichetti
unfortunately the thoughts are a bit misplaced

the ts posted the requirement and snippets in different languages that build the required buffer
click on the link to the zabbix manual page

the Rexx snippets build the buffer according to the specifications
to be sure I run the bash snippets and the result agree
it looks strange with the code tags because to deal with bit/hex chars in other language you have to escape them

the only thing to check id the sequence of the socket commands used for the conversation

Re: Communicating with Zabbix from REXX

PostPosted: Sat Mar 13, 2021 12:29 pm
by AllardK
Hello,

the REXX code works fine with Zabbix when I run it on linux, however the problem only exists running from z/OS.

Also the java version runs fine on z/OS and communicates with Zabbix.

My conclusion is that somtehing goed wrong in the REXX socket EBCDIC ASCII conversion.

Continuing my research....

Kind regards Allard

Re: Communicating with Zabbix from REXX

PostPosted: Sat Mar 13, 2021 2:40 pm
by enrico-sorichetti
My conclusion is that somtehing goed wrong in the REXX socket EBCDIC ASCII conversion.


IMO the real problem is that the buffer contains binary and char data
so there should not be any EBCDIC/ASCII conversion ...

You might try to set the socket option to send the data as binary ....

the point I am trying to make and you should deal with is ...

on zOS you build a mixed EBCDIC/binary buffer
on Linux you build a mixed ASCII/binary buffer

sending the buffer with the translation enabled will f**k up the binary data
sending the buffer as binary will let zabbix deal correctly with the lengths, but what about the textual EBCDIC/ASCII part ???
I am no java expert, could it be that the java snippet builds the text as ascii and not ebcdic
translating to ascii is not that difficult, just add one function call , you have only to find the correct translation table

Re: Communicating with Zabbix from REXX

PostPosted: Sat Mar 13, 2021 3:45 pm
by AllardK
Hello Enrico, Willy and Pedro,

thanks for all your tips and hints!

I solved the problem this morning.

i removed automatic EBCDIC to ASCII conversion at the socket-level.
i did the conversion of the input from ASCII to EBCDIC using my own REXX-code.
I converted parts of the output-string to ASCII using my own REXX-code.
I left the binary part of the output-string untouched.

This is the code that works:


  read_string_e = ASCII_to_EBCDIC(read_string)
  key = DELSTR(read_string_e,1,13)
  r = Calculate_Result(key)
  l = length(r)
  packet_p1  = EBCDIC_to_ASCII('ZBXD'||D2C(1,1))
  packet_p2 = D2C(l,1)||D2C(0,1)||D2C(0,1)||D2C(0,1)||'00000000'x
  packet_p3 = EBCDIC_to_ASCII(r)
  packet = packet_p1||packet_p2||packet_p3
 


Again thanks for all your help!

Kind regards Allard

Re: Communicating with Zabbix from REXX

PostPosted: Fri Mar 26, 2021 6:11 pm
by AllardK
Hi readers,

now thet I have my Zabbix Agent working on z/OS I want to enhance it by reading a zabbix config file.

I found some sample code on RosettaCode:

/*REXX program reads a config (configuration) file and assigns  VARs  as found within.  */
signal on syntax;      signal on novalue         /*handle REXX source program errors.   */
parse arg cFID _ .                               /*cFID:  is the CONFIG file to be read.*/
if cFID==''  then cFID='CONFIG.DAT'              /*Not specified?  Then use the default.*/
bad=                                             /*this will contain all the  bad VARs. */
varList=                                         /*  "    "     "     "   "  good   "   */
maxLenV=0;   blanks=0;   hashes=0;   semics=0;   badVar=0    /*zero all these variables.*/

   do j=0  while lines(cFID)\==0                 /*J:   it counts the lines in the file.*/
   txt=strip(linein(cFID))                       /*read a line (record) from the file,  */
                                                 /*  ··· & strip leading/trailing blanks*/
   if      txt    =''    then do; blanks=blanks+1; iterate; end   /*count # blank lines.*/
   if left(txt,1)=='#'   then do; hashes=hashes+1; iterate; end   /*  "   " lines with #*/
   if left(txt,1)==';'   then do; semics=semics+1; iterate; end   /*  "   "   "     "  ;*/
   eqS=pos('=',txt)                              /*we can't use the   TRANSLATE   BIF.  */
   if eqS\==0  then txt=overlay(' ',txt,eqS)     /*replace the first  '='  with a blank.*/
   parse var txt xxx value;  upper xxx           /*get the variable name and it's value.*/
   value=strip(value)                            /*strip leading and trailing blanks.   */
   if value='' then value='true'                 /*if no value,  then use   "true".     */
   if symbol(xxx)=='BAD'  then do                /*can REXX utilize the variable name ? */
                               badVar=badVar+1;  bad=bad xxx;  iterate  /*append to list*/
                               end
   varList=varList xxx                           /*add it to the list of good variables.*/
   call value xxx,value                          /*now,  use VALUE to set the variable. */
   maxLenV=max(maxLenV,length(value))            /*maxLen of varNames,  pretty display. */
   end   /*j*/

vars=words(varList);          @ig= 'ignored that began with a'
                    say #(j)       'record's(j) "were read from file: " cFID
if blanks\==0  then say #(blanks)  'blank record's(blanks) "were read."
if hashes\==0  then say #(hashes)  'record's(hashes)   @ig   "#  (hash)."
if semics\==0  then say #(semics)  'record's(semics)   @ig   ";  (semicolon)."
if badVar\==0  then say #(badVar)  'bad variable name's(badVar) 'detected:' bad
say;  say 'The list of'    vars    "variable"s(vars)    'and'    s(vars,'their',"it's"),
                                   "value"s(vars)       'follows:'
say;          do k=1  for vars
              v=word(varList,k)
              say  right(v,maxLenV) '=' value(v)
              end   /*k*/
say;  exit                                       /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
s:       if arg(1)==1  then return arg(3);               return word(arg(2) 's',1)
#:       return right(arg(1),length(j)+11)       /*right justify a number & also indent.*/
err:       do j=1  for arg();  say '***error***    ' arg(j);  say;  end  /*j*/;    exit 13
novalue: syntax:   call err 'REXX program' condition('C') "error",,
         condition('D'),'REXX source statement (line' sigl"):",sourceline(sigl)


It is the part that sets the value of the compound variable that gives a syntax-error on z/OS

  call value xxx,value


Can anybody help me to code this functionality in REXX on z/OS?

And believe me! I have read the manuals and tutorials but found no solution yet.

Thanks for your help in advance.

Kind regards Allard

Re: Communicating with Zabbix from REXX

PostPosted: Fri Mar 26, 2021 7:45 pm
by enrico-sorichetti
remember... we reply on our own time and free of charge

if You want people to be helpful You should learn to post
FIRST a clear description of the requrement
AFTER if You tried and did not succeed a readable code snippet of your attempt

we spend time trying to understand people requrement logic and provide reasonable solutions
we should be spared the hassle of trying to demangle unreadable code to get the requirement

it might be clear for You
it will be a nightmare for people that will have to maintain it in the future

good luck !

the best thing would be - using the code tags where appropriate

a sampe of the input,
a sample of the output, or a clear description of the process
the significance of white spaces

Re: Communicating with Zabbix from REXX

PostPosted: Fri Mar 26, 2021 10:41 pm
by AllardK
Ok i will give it a try:

I want to read a config file (PDS-member) into my REXX-program.
Then I want to create a coupound variable that contains the config variables and their values.


/* REXX */
/*read PDS-member ZABXCONF into stem zabxconf*/
address TSO
"alloc DA(IBMUSER.PROGRAMS.REXX(ZABXCONF)) shr file(input)"
"execio * diskr input (stem zabxconf. finis)"
"free file(input)"

/*initialise compound list of variables and their values*/
CONFIGVARLIST=

/* loop trough all items in the stem zabxconf */
do j=0  to zabxconf.0
       /*  ··· & strip leading/trailing blanks*/
       txt = strip(zabxconf.j)
      parse var txt configvariable configvalue
      upper configvariable
     /*add it to the list of variables.*/
      CONFIGVARLIST = CONFIGVARLIST configvariable
      /*now,  use VALUE to set the variable. */
      CALL VALUE configvariable, configvalue      
end
 


Running the program gives an error on the CALL VALLUE statement:

“Incorrect call to routine”

What is the correct syntax for REXX on z/os to assign the value to the variable?

Kind regards

Allard

Re: Communicating with Zabbix from REXX

PostPosted: Fri Mar 26, 2021 11:51 pm
by enrico-sorichetti
the how


line.1 = "aaaa xxxx"
line.2 = "bbbb yyyy"
line.0 = 2

do i = 1 to line.0
  parse var line.i argn argv
  interpret argn "= argv"
end
say
say "after interpret"
say "aaaa" aaaa
say "bbbb" bbbb


do i = 1 to line.0
  parse var line.i argn argv
  call value argn, argv
end
say
say "after value"
say "aaaa" aaaa
say "bbbb" bbbb


the result


after interpret
aaaa xxxx
bbbb yyyy

after value
aaaa xxxx
bbbb yyyy
 

Re: Communicating with Zabbix from REXX

PostPosted: Sat Mar 27, 2021 1:29 pm
by AllardK
Hello Enrico,

thanks a lot for your help!

By using your exampe in combination with my code I found out that the problem was not in the statement CALL VALUE.

It was a bit trickier than that: the problem was that I started the loop building the compound variable with j=0 instead of j=1

That caused an error beacause that stemvariable.0 is used for the number of compound variables in the stem and does not contain a config variable and a value, just a number.

Again thanks for your help, I was beginning to doubt my understanding of REXX compound variables.

Kind regards Allard

Re: Communicating with Zabbix from REXX

PostPosted: Sat Mar 27, 2021 5:14 pm
by willy jensen
Glad you found the cause.
The proper way to use VALUE to assign a value to a variable is v=VALUE(varname,value).
Sample from a actual program:

idanamel  = 'SEL 3 NAME 44 QUAL2 8 TYPE 8'  /* name length pairs       */
idanames=''                                                              
do i=1 to words(idanamel) by 2                                            
  n=word(idanamel,i)                                                      
  zz=Value('IDAF'n'L',word(idanamel,i+1))  /* generate length variable */
  idanames=idanames n                      /* make list of names only  */
end                                                                      
 

The 'v' doesnt normally matter as it will contain the variables prior value.