How to read the first line from a file?

34 views
Skip to first unread message

Aleksey Tsalolikhin

unread,
Sep 2, 2015, 9:11:07 PM9/2/15
to help-cfengine
Is there a simpler way to do this in native CFEngine code?

{{{

vars:

   "os"
       slist => splitstring(readfile("/etc/issue", 99), "\n", 1);

}}}

I was kind of thinking readline("/path/to/file", 1) but there is no readline() function


--
Aleksey Tsalolikhin
CFEngine Training & Consulting
Vertical Sysadmin, Inc.

Neil Watson

unread,
Sep 2, 2015, 9:19:57 PM9/2/15
to help-cfengine
On Wed, Sep 02, 2015 at 06:10:46PM -0700, Aleksey Tsalolikhin wrote:
> Is there a simpler way to do this in native CFEngine code?
> {{{
> vars:
>    "os"
>        slist => splitstring(readfile("/etc/issue", 99), "\n", 1);
> }}}
> I was kind of thinking readline("/path/to/file", 1) but there is no
> readline() function

readstringlist?

https://docs.cfengine.com/latest/reference-functions-readintrealstringlist.html

--
Neil H Watson
Sr. Partner, Architecture and Infrastructure
CFEngine reporting: https://github.com/evolvethinking/delta_reporting
CFEngine policy: https://github.com/evolvethinking/evolve_cfengine_freelib
CFEngine and vim: https://github.com/neilhwatson/vim_cf3
CFEngine support: http://evolvethinking.com

Aleksey Tsalolikhin

unread,
Sep 3, 2015, 2:37:31 PM9/3/15
to Neil Watson, help-cfengine
On Wed, Sep 2, 2015 at 6:19 PM, Neil Watson <cfen...@watson-wilson.ca> wrote:
On Wed, Sep 02, 2015 at 06:10:46PM -0700, Aleksey Tsalolikhin wrote:
  Is there a simpler way to do this in native CFEngine code?
  {{{
  vars:
     "os"
         slist => splitstring(readfile("/etc/issue", 99), "\n", 1);
  }}}
  I was kind of thinking readline("/path/to/file", 1) but there is no
  readline() function

readstringlist?

https://docs.cfengine.com/latest/reference-functions-readintrealstringlist.html

Yeah, I thought so too but I couldn't understand how to use it.  :(

The example is incomplete, it shows the RHS but not the LHS:

Example:

    readintarray("array_name","/tmp/array","#[^\n]*",":",10,4000);

Aside: If I didn't have to sleep, I would go through the documentation and make the examples (more) comprehensible by making them runnable.

I tried to work it out, and this is what I got:

{{{
# cat test.cf
bundle agent example 
{

vars:
   "some_integer"
       int => readintarray("array_name","/tmp/array","#[^\n]*",":",10,4000);
   "indices"
       slist => getindices("array_name");

reports:
  "Indices = $(indices)";
  "Array contents = $(array_name[$(indices)])";
}
# cf-agent -f ./test.cf -b example -K
R: Indices = 4
R: Indices = 3
R: Indices = 1
R: Indices = 2
R: Array contents = $(array_name[4])
R: Array contents = $(array_name[3])
R: Array contents = $(array_name[1])
R: Array contents = $(array_name[2])
#
}}}

I feel like I'm halfway there...

Nick Anderson

unread,
Sep 3, 2015, 2:40:25 PM9/3/15
to Aleksey Tsalolikhin, Neil Watson, help-cfengine
On 09/03/2015 01:37 PM, Aleksey Tsalolikhin wrote:
> "Array contents = $(array_name[$(indices)])";

Can you provide the sample input data?

Without trying myself, perhaps $(array_name[$(indices)][0]) or
$(array_name[$(indices)][1])

Aleksey Tsalolikhin

unread,
Sep 3, 2015, 2:45:03 PM9/3/15
to Nick Anderson, Neil Watson, help-cfengine
Thanks, Nick, I think that did it:

# cat /tmp/array 
1: 5:7:21:13
2:19:8:14:14
3:45:1:78:22
4:64:2:98:99
# cat test.cf 
bundle agent example 
{

vars:
   "some_integer"
       int => readintarray("array_name","/tmp/array","#[^\n]*",":",10,4000);
   "indices"
       slist => getindices("array_name");

reports:
  "Indices = $(indices)";
  "First element = $(array_name[$(indices)][0])";
  "Second element = $(array_name[$(indices)][1])";
  "Third element = $(array_name[$(indices)][2])";
}
# cf-agent -f ./test.cf -b example -K
R: Indices = 4
R: Indices = 3
R: Indices = 1
R: Indices = 2
R: First element = 4
R: First element = 3
R: First element = 1
R: First element = 2
R: Second element = 64
R: Second element = 45
R: Second element = 5
R: Second element = 19
R: Third element = 2
R: Third element = 1
R: Third element = 7
R: Third element = 8


Neil Watson

unread,
Sep 3, 2015, 2:56:24 PM9/3/15
to help-cfengine
I may not understand your desire, but:

body common control
{
bundlesequence => { "main", };
}

bundle agent main
{
vars:
"hosts_line_one" slist => readstringlist(
"/etc/hosts",
"^\s#",
"\n",
"1",
"10"
);

reports:
"line => ${hosts_line_one}";
}

Produces:
R: line => 127.0.0.1

Aleksey Tsalolikhin

unread,
Sep 3, 2015, 3:14:07 PM9/3/15
to Neil Watson, help-cfengine
Lovely, thanks, Neil!

Now I can harvest the OS id (e.g. 'CentOS release 6.6 (Final)') to add to inventory.

(I don't have "lsb_release" command so I have to harvest the OS name and version from /etc/issue.)


{{{
  vars:
     "etc_issue_line_one"
       slist => readstringlist(
                               "/etc/issue", 
                               "^\s#", # regex matching comments
                               "\n",   # regex to split lines into fields
                               "1",    # maxentries
                               "80"    # maximum bytes to read
                               ),
       comment => "Read the first line from the OS banner in
                   /etc/issue to get OS name and version";

     "os_banner"
       comment => "Convert slist to string so it looks pretty in Inventory UI",
       string => join("", "etc_issue_line_one"),
       meta => { "inventory", "attribute_name=OS Name and Version" };

}}}

--
You received this message because you are subscribed to the Google Groups "help-cfengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to help-cfengin...@googlegroups.com.
To post to this group, send email to help-c...@googlegroups.com.
Visit this group at http://groups.google.com/group/help-cfengine.
For more options, visit https://groups.google.com/d/optout.

Neil Watson

unread,
Sep 3, 2015, 3:19:29 PM9/3/15
to help-cfengine
On Thu, Sep 03, 2015 at 12:13:46PM -0700, Aleksey Tsalolikhin wrote:
> Lovely, thanks, Neil!
> Now I can harvest the OS id (e.g. 'CentOS release 6.6 (Final)') to add
> to inventory.
> (I don't have "lsb_release" command so I have to harvest the OS name and
> version from /etc/issue.)

Issue is often changed by sysadmins. It should not be relied on. Why are
trying to get this? Isn't it already a hard class: centos_6_6?

Aleksey Tsalolikhin

unread,
Sep 4, 2015, 11:36:57 AM9/4/15
to Neil Watson, help-cfengine
On Sep 3, 2015 12:19 PM, "Neil Watson" <cfen...@watson-wilson.ca> wrote:

Issue is often changed by sysadmins. It should not be relied on. Why are
trying to get this? Isn't it already a hard class: centos_6_6?

I did try using hard classes originally (a few months ago) but it didn't work on all the kinds servers I have to support.  I don't remember what the outlier was but I resorted to parsing /etc/issue, which, as you say, is liable to being modified by local staff.

I may revisit this.  I was under a lot of pressure at the time to get the thing working quickly. The advantage of using all hard classes would be the policy would run faster and we'd get rid of this potential liability.

Brian Bennett

unread,
Sep 4, 2015, 12:44:34 PM9/4/15
to Aleksey Tsalolikhin, Neil Watson, help-cfengine
Is $(sys.os) not correct?

-- 
Brian Bennett
Looking for CFEngine training?
--

Aleksey Tsalolikhin

unread,
Sep 4, 2015, 2:07:19 PM9/4/15
to Brian Bennett, Neil Watson, help-cfengine
On Fri, Sep 4, 2015 at 9:45 AM, Brian Bennett <brian....@verticalsysadmin.com> wrote:
Is $(sys.os) not correct?

sys.os

The name of the operating system according to the kernel.

# os = linux

 
Oh, it's correct, but all my operating systems are "linux", Brian.   :-)  I need to know the distribution name (e.g. RHEL or CentOS or Oracle Enterprise Linux, etc.) and the version of the distribution.

Do I smell the need for $(sys.os_name) and $(sys.os_version) ?   I bet that would be useful in inventory in many sites.

Eystein Måløy Stenberg

unread,
Sep 4, 2015, 2:10:04 PM9/4/15
to help-c...@googlegroups.com
There is $(inventory_os.description) that uses LSB if available. Or you
can use $(sys.flavor).

On 04/09/15 11:06, Aleksey Tsalolikhin wrote:
> On Fri, Sep 4, 2015 at 9:45 AM, Brian Bennett
> <brian....@verticalsysadmin.com
> --
> You received this message because you are subscribed to the Google
> Groups "help-cfengine" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to help-cfengin...@googlegroups.com
> <mailto:help-cfengin...@googlegroups.com>.
> To post to this group, send email to help-c...@googlegroups.com
> <mailto:help-c...@googlegroups.com>.
> Visit this group at http://groups.google.com/group/help-cfengine.
> For more options, visit https://groups.google.com/d/optout.

--

Eystein

Aleksey Tsalolikhin

unread,
Sep 4, 2015, 2:57:21 PM9/4/15
to Eystein Måløy Stenberg, help-cfengine
On Fri, Sep 4, 2015 at 11:09 AM, Eystein Måløy Stenberg <eystein.mal...@cfengine.com> wrote:
There is $(inventory_os.description) that uses LSB if available.

Thank you, but LSB is not available.  =)  
 
Or you can use $(sys.flavor).

sys.flavor, sys.flavour

A variable containing an operating system identification string that is used to determine the current release of the operating system in a form that can be used as a label in naming. This is used, for instance, to detect which package name to choose when updating software binaries for CFEngine.
 

$ cf-agent -f ./temp.cf -b example
R: redhat_6
$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 6.2 (Santiago)
$

# cf-agent -f ./temp.cf -b example
R: centos_6
# cat /etc/centos-release 
CentOS release 6.6 (Final)

I need to inventory the release of the operating system (i.e. number of RHEL 6.2 versus number of RHEL 6.6).

I would expect a CFEngine system variable that would provide the release version of the operating system (such as 6.6). =)  


 

Brian Bennett

unread,
Sep 4, 2015, 2:58:54 PM9/4/15
to Aleksey Tsalolikhin, Neil Watson, help-cfengine
I would go for sys.distribution.

In the mean time, I'd recommend making a module that can emit extra variables. Something similar to what I do for Triton/SmartOS metadata (https://github.com/bahamat/cfengine-smartos-metadata).


-- 
Brian Bennett
Looking for CFEngine training?

Brian Bennett

unread,
Sep 4, 2015, 3:00:58 PM9/4/15
to Aleksey Tsalolikhin, Eystein Måløy Stenberg, help-cfengine
In the past I used classes for that kind of thing. E.G., redhat_6_2 vs redhat_6_6.


-- 
Brian Bennett
Looking for CFEngine training?
--
You received this message because you are subscribed to the Google Groups "help-cfengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to help-cfengin...@googlegroups.com.
To post to this group, send email to help-c...@googlegroups.com.

Aleksey Tsalolikhin

unread,
Sep 6, 2015, 5:54:15 PM9/6/15
to Brian Bennett, Eystein Måløy Stenberg, help-cfengine
On Fri, Sep 4, 2015 at 12:02 PM, Brian Bennett <brian....@verticalsysadmin.com> wrote:
In the past I used classes for that kind of thing. E.G., redhat_6_2 vs redhat_6_6.

Right.  Here's what I've concocted to inventory the OS distribution (name and major.minor version number):

      "os_name"
        slist => { "redhat", "centos", "oracle" };

      "major"
        slist  => { "4", "5", "6", "7" };

      "minor"
        slist  => { "1", "2", "3", "4" , "5", "6", "7", "8", "9", "10" };

      "detailed_flavor"
        string => "$(os_name) $(major).$(minor)",
        ifvarclass => "$(os_name)_$(major)_$(minor)",
        meta => { "inventory", "attribute_name=OS Flavor by Name and Major.Minor" };

In action:

R:      DEBUG inventory_redhat_version: Added to inventory: 'OS Flavor by Name and Major.Minor' = 'redhat 6.2'

Thanks for the help, all!

Best,
-at

Reply all
Reply to author
Forward
0 new messages