Skip to content

Instantly share code, notes, and snippets.

@nickanderson
Created July 16, 2019 17:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nickanderson/4d88deb05b350643f6526d16f84fcac5 to your computer and use it in GitHub Desktop.
Save nickanderson/4d88deb05b350643f6526d16f84fcac5 to your computer and use it in GitHub Desktop.

[#A]IRC: Investigate Error from format() function

i am getting aq funny error, i think its from this code

bundle agent init
{
  files:
    "/var/cfengine/billing/$(main.peers)/$(main.year)-$(main.month)"
      edit_line => insert_line( '{ "some-data": "$(peers)" }' ),
      create => "true";
      
}
bundle edit_line insert_line( line )
{
  insert_lines:
    "$(line)";
}
bundle agent main
{
  vars:
    "peers" slist => { "one", "two" };
    "year" string => strftime( localtime, "%Y", now() );
    "month" string => strftime( localtime, "%m", now() );

  "invoices[$(peers)]"
    string => format( "%S", readdata("/var/cfengine/billing/$(peers)/$(year)-$(month)", "auto") ),
    if => fileexists( "/var/cfengine/billing/$(peers)/$(year)-$(month)" );
}
error: format() didn't have enough parameters

I think the error with format() is that it is not a collecting function.

Also, I don’t think that you have to stuff JSON strings into classic arrays in order to be able to iterate and process them. The meta attribute combined with =variablesmatching()= or =variablesmatching_as_data()= can be useful to pull together various data containers.

Here I switched from a classic array to individual data containers for each data file. Each variable is tagged with invoice so that they can all be collected together into a unified data container.

bundle agent init
{
  files:
    "/var/cfengine/billing/$(main.peers)/$(main.year)-$(main.month)"
      edit_line => insert_line( '{ "some-data": "$(main.peers)" }' ),
      create => "true";
      
}
bundle edit_line insert_line( line )
{
  insert_lines:
    "$(line)";
}
bundle agent main
{
  vars:
    "peers" slist => { "one", "two" };
    "year" string => strftime( localtime, "%Y", now() );
    "month" string => strftime( localtime, "%m", now() );

  "invoices_$(peers)"
    meta => { invoice },
    data => readdata("/var/cfengine/billing/$(peers)/$(year)-$(month)", "JSON"),
    if => fileexists( "/var/cfengine/billing/$(peers)/$(year)-$(month)" );

  "unified_invoices"
    data => variablesmatching_as_data( ".*",       # Variables with any name, in any bundle, in any namespace
                                       "invoice"); # Tagged with invoice

  reports:
    "CFEngine $(sys.cf_version)";
    
}
[root@hub ~]# cf-agent -KIf ./t.cf --show-evaluated-vars=main
R: CFEngine 3.12.2
Variable name                            Variable value                                               Meta tags                               
default:main.invoices_one                {"some-data":"one"}                                          source=promise,invoice                  
default:main.invoices_two                {"some-data":"two"}                                          source=promise,invoice                  
default:main.month                       07                                                           source=promise                          
default:main.peers                        {"one","two"}                                               source=promise                          
default:main.unified_invoices            {"default:main.invoices_one":{"some-data":"one"},"default:main.invoices_two":{"some-data":"two"}} source=promise                          
default:main.year                        2019                                                         source=promise                          
default:sys.domain                       example.com                                                  source=agent              

See CFE-3105 for issue tracking adding collecting behavior to the format() function.

Example showing format should take functions that return data.

bundle agent main
{
  vars:
    "peers" slist => { "one", "two" };
    "year" string => strftime( localtime, "%Y", now() );
    "month" string => strftime( localtime, "%m", now() );

    "$(peers)" data => '{ "some-data": "$(peers)" }';

  "WORKS[$(peers)]"
    string => format( "%S", "$(peers)" );

  "ERRORS[$(peers)]"
    string => format( "%S", parsejson( '{ "some-data": "$(peers)" }' ) );
}
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
   error: format() didn't have enough parameters
Variable name                            Variable value                                               Meta tags                               
default:main.WORKS[one]                  {\"some-data\":\"one\"}                                      source=promise                          
default:main.WORKS[two]                  {\"some-data\":\"two\"}                                      source=promise                          
default:main.month                       07                                                           source=promise                          
default:main.one                         {"some-data":"one"}                                          source=promise                          
default:main.peers                        {"one","two"}                                               source=promise                          
default:main.two                         {"some-data":"two"}                                          source=promise                          
default:main.year                        2019                                                         source=promise                          
default:maintain_key_values_meta.tags     {"deprecated=3.6.0","deprecation-reason=Generic reimplementation","replaced-by=set_line_based"} source=promise                          

Ok, but what if $(peers) contains characters that are not valid in variable names?

Then you need to make a canonified map that you can use for iteration.

bundle agent init
{
  files:
    "/var/cfengine/billing/$(main.peers)/$(main.year)-$(main.month)"
      edit_line => insert_line( '{ "some-data": "$(main.peers)" }' ),
      create => "true";
      
}
bundle edit_line insert_line( line )
{
  insert_lines:
    "$(line)";
}
bundle agent main
{
  vars:
    "peers" slist => { "one-crap", "two.balls" };

    "cmap_peers[$(peers)]" string => canonify( $(peers) );

    "year" string => strftime( localtime, "%Y", now() );
    "month" string => strftime( localtime, "%m", now() );

  "invoices_$(cmap_peers[$(peers)])"
    meta => { invoice },
    data => readdata("/var/cfengine/billing/$(peers)/$(year)-$(month)", "JSON"),
    if => fileexists( "/var/cfengine/billing/$(peers)/$(year)-$(month)" );

  "unified_invoices"
    data => variablesmatching_as_data( ".*",       # Variables with any name, in any bundle, in any namespace
                                       "invoice"); # Tagged with invoice

  reports:
    "CFEngine $(sys.cf_version)";
    
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment