Merge pull request 'feat: add nodelookup' (#90) from neoloc/nodelookup into develop

Reviewed-on: unkinben/puppet-prod#90
This commit is contained in:
Ben Vincent 2023-12-11 19:47:23 +09:30
commit 7f270675b1
3 changed files with 118 additions and 0 deletions

View File

@ -35,6 +35,7 @@ class profiles::base (
include profiles::dns::base
include profiles::cloudinit::init
include profiles::metrics::default
include profiles::helpers::node_lookup
# include the python class
class { 'python':

View File

@ -0,0 +1,56 @@
# profiles::helpers::node_lookup
#
# wrapper class for python, pip and venv
class profiles::helpers::node_lookup (
String $script_name = 'node_lookup',
Stdlib::AbsolutePath $base_path = "/opt/${script_name}",
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
String $owner = 'root',
String $group = 'root',
Boolean $systempkgs = false,
String $version = 'system',
Array[String[1]] $packages = ['requests'],
){
# ensure the base_path exists
file { $base_path:
ensure => directory,
mode => '0755',
owner => $owner,
group => $group,
}
# create a venv
python::pyvenv { $venv_path :
ensure => present,
version => $version,
systempkgs => $systempkgs,
venv_dir => $venv_path,
owner => $owner,
group => $group,
require => File[$base_path],
}
# install the required pip packages
$packages.each |String $package| {
python::pip { "${venv_path}_${package}":
ensure => present,
pkgname => $package,
virtualenv => $venv_path,
}
}
# create the script from a template
file { "${base_path}/${script_name}":
ensure => file,
mode => '0755',
content => template("profiles/helpers/${script_name}.erb"),
require => Python::Pyvenv[$venv_path],
}
# create symbolic link in $PATH
file { "/usr/local/bin/${script_name}":
ensure => 'link',
target => "${base_path}/${script_name}",
require => File["${base_path}/${script_name}"],
}
}

View File

@ -0,0 +1,61 @@
#!/usr/bin/env <%= @venv_path %>/bin/python
import requests
import sys
import argparse
import json
def build_query(node=None, fact_name=None, match=None, show_role=False):
query_filters = []
if node:
query_filters.append(["=", "certname", node])
if fact_name:
query_filters.append(["=", "name", fact_name])
elif show_role:
query_filters.append(["=", "name", "enc_role"])
if match:
query_filters.append(["~", "value", match])
if not query_filters:
return '["=", "name", "enc_role"]'
else:
return json.dumps(["and"] + query_filters)
def query_puppetdb(query):
url = 'http://puppetdb:8080/pdb/query/v4/facts'
response = requests.get(url, params={'query': query})
process_response(response)
def process_response(response):
if response.status_code == 200:
for fact in response.json():
print(f"{fact['certname']} {fact['value']}")
else:
print(f"Error querying PuppetDB: HTTP {response.status_code}")
print("Response content:", response.text)
def parse_stdin():
for line in sys.stdin:
yield line.split()[0]
def main():
parser = argparse.ArgumentParser(description="Query PuppetDB for nodes.")
parser.add_argument("-n", "--node", help="Node name or partial match")
parser.add_argument("-R", "--role", action="store_true", help="Show the role for matched hosts")
parser.add_argument("-F", "--fact", help="Specify a fact name")
parser.add_argument("-m", "--match", help="Simple pattern match for the value")
args = parser.parse_args()
if not args.node and not sys.stdin.isatty():
for node in parse_stdin():
args.node = node
query = build_query(node=args.node, fact_name=args.fact, match=args.match, show_role=args.role)
query_puppetdb(query)
else:
query = build_query(node=args.node, fact_name=args.fact, match=args.match, show_role=args.role)
query_puppetdb(query)
if __name__ == "__main__":
main()