fboender / ansible-cmdb

Generate host overview from ansible fact gathering output
GNU General Public License v3.0
2.35k stars 467 forks source link

Support for packages version #155

Closed yodatak closed 6 years ago

yodatak commented 6 years ago

This tool is great but i can't find maybe its possible but i did not find it. To have a listing of version of differents packages like apache version postgresql version and kernel version . It's could be verry interesting to have a listing of some packages to security interest or for info. Is there is a way to this know with ansible-cmdb ?

yodatak commented 6 years ago

Maybe we could use the package_facts on ansible 2.5 https://github.com/ansible/ansible/pull/33195

yodatak commented 6 years ago

Hi some news on my try : I used this packages_facts on ansible 2.5.0 :

sudo pip install ansible==2.5.0rc1
sudo pip install ansible-cmdb
ansible -m package_facts --tree outpackage/ all 
ansible-cmdb -t json outpackage/ > overview.json
ansible-cmdb -t txt_table outpackage/ > overview.txt

The raw file of the output :

I cut it because is way tooooo long

{"ansible_facts": {"packages": {"AcetoneISO": [{"arch": "x86_64", "epoch": null, "name": "AcetoneISO", "release": "24.fc27", "source": "rpm", "version": "6.7"}], "zziplib": [{"arch": "x86_64", "epoch": null, "name": "zziplib", "release": "1.fc27", "source": "rpm", "version": "0.13.68"}]}}, "changed": false}

The json file is good

{
  "localhost": {
    "changed": false, 
    "hostvars": {}, 
    "name": "localhost", 
    "ansible_facts": {
      "packages": {
        "kde-platform-plugin": [
          {
            "name": "kde-platform-plugin", 
            "source": "rpm", 
            "epoch": 1, 
            "version": "4.11.22", 
            "release": "20.fc27", 
            "arch": "x86_64"
          }
        ], 
        "texlive-gmutils": [
          {
            "name": "texlive-gmutils", 
            "source": "rpm", 
            "epoch": 6, 
            "version": "svn24287.v0.996", 
            "release": "36.fc27.5", 
            "arch": "noarch"
          }
        ]
      }
    }
  }
}

I try to make a custom template with a new template txt_table_packages.tpl

I add this line in the cols = {"title": "Apache", "id": "apache", "visible": True, "field": lambda h: host['ansible_facts'].get('packages', {}).get('apache', [{}]).get('version', '')},

On the folder example in the ansible-cmdb master i run ../src/ansible-cmdb -d -q -t txt_table_packages -i hosts outpackage

and i got

The reported error was: AttributeError: 'list' object has no attribute 'get'

The full error was:

    Traceback (most recent call last):
      File "../src/ansible-cmdb", line 177, in <module>
        output = renderer.render(ansible.hosts, params)
      File "/home/yodatak/github/ansible-cmdb/src/ansiblecmdb/render.py", line 42, in render
        return self._render_mako(hosts, vars)
      File "/home/yodatak/github/ansible-cmdb/src/ansiblecmdb/render.py", line 59, in _render_mako
        return template.render(hosts=hosts, **vars)
      File "/usr/lib/python2.7/site-packages/mako/template.py", line 462, in render
        return runtime._render(self, self.callable_, args, data)
      File "/usr/lib/python2.7/site-packages/mako/runtime.py", line 838, in _render
        **_kwargs_for_callable(callable_, data))
      File "/usr/lib/python2.7/site-packages/mako/runtime.py", line 873, in _render_context
        _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
      File "/usr/lib/python2.7/site-packages/mako/runtime.py", line 899, in _exec_template
        callable_(context, *args, **kwargs)
      File "/home/yodatak/github/ansible-cmdb/src/ansiblecmdb/data/tpl/txt_table_packages.tpl", line 1, in render_body
        <%
      File "/home/yodatak/github/ansible-cmdb/src/ansiblecmdb/data/tpl/txt_table_packages.tpl", line 1, in <lambda>
        <%
    AttributeError: 'list' object has no attribute 'get'

The output is probably not correct.

I think the error is [{"arch": "x86_64", "epoch": null, "name": "AcetoneISO", "release": "24.fc27", "source": "rpm", "version": "6.7"}], close to the [{ but i'm not sure any people can help me on this and maybe mainstream it on the next version of ansible-cmdb ?

yodatak commented 6 years ago

I use a output where i remove all the [] and its works with : {"ansible_facts": {"packages": {"apache": {"arch": "x86_64", "epoch": null, "name": "apache", "release": "24.fc27", "source": "rpm", "version": "2.4"}, "zziplib": {"arch": "x86_64", "epoch": null, "name": "zziplib", "release": "1.fc27", "source": "rpm", "version": "0.13.68"}}}, "changed": false}

In my tpl i got : {"title": "Apache", "id": "apache", "visible": True, "field": lambda h: host['ansible_facts'].get('packages', {}).get('apache', {}).get('version', '')},

I think the [] are present in the ansible module for multiple packages version like in the kernel

Did i'm wrong ? poke @fboender ?

fboender commented 6 years ago

Hi yodatak,

You're on the right track with the ansible_facts. The fancy_html template supports them out of the box. The problem with your custom template is in this part:

get('apache', [{}])

This returns an empty dictionary in a list. You then try to do this on that result:

.get('version', '')

The .get method doesn't exist on a list. You should change the get('apache', [{}]) part to:

get('apache', [{}])[0]

To retrieve the first result from the list. I think that should solve the problem.

yodatak commented 6 years ago

hi thanks for your help fboender with {"title": "apache", "id": "apache", "visible": True, "field": lambda h: host['ansible_facts'].get('packages', {}).get('apache', [{}])[0].get('version', '')}, i obtain the good version , by the way i'm not sure its works with multilib like this

"zlib": [
                {
                    "arch": "x86_64",
                    "epoch": null,
                    "name": "zlib",
                    "release": "29.el6",
                    "source": "rpm",
                    "version": "1.2.3"
                },
                {
                    "arch": "i686",
                    "epoch": null,
                    "name": "zlib",
                    "release": "29.el6",
                    "source": "rpm",
                    "version": "1.2.3"
                }
            ]

On the html_fancy_defs.html

i use this

<%def name="col_apache(host, **kwargs)">
  ${jsonxs(host, 'ansible_facts.packages.apache.version', default='')}
</%def>
and this 
{"title": "Apache",        "id": "apache",        "func": col_apache,         "sType": "string", "visible": True},

But it don't show apache but the rest.

Another thing its in using the module ansible -m package_facts --tree outpackage/ all its don't take the setup facts so we don't have any info like ip and so on . Can it be possible to do all in one and have this in the interface

fboender commented 6 years ago

by the way i'm not sure its works with multilib like this

html_fancy_defs uses a recursive algorithm to dump the custom and host local facts. It doesn't care at all about the actual structure, so it should work.

Can it be possible to do all in one and have this in the interface

What I usually do is generate the facts on the hosts themselves in a cronjob and put them all in /etc/ansible/facts.d directory. Ansible's setup module than automatically included all of the facts in there, including the normal system facts.

You can also specify multiple "out" directories when invoking ansible-cmdb, so it may be possible to do:

ansible -m package_facts --tree outpackage/ all
ansible -m setup --tree outsetup/ all
ansible-cmdb -i hosts outsetup outpacakge > cmdb.html

But I haven't tested that, so I'm not sure if it'll work properly.

One last potential option: it might be possible to do something like:

ansible -m package_facts -m setup all

Again, completely untested, and it depends entirely on if ansible supports that.