Skip to content

Commit

Permalink
Added nt-discovery.sh to get information about host
Browse files Browse the repository at this point in the history
Ticket: ENT-12576
Signed-off-by: Victor Moene <victor.moene@northern.tech>
  • Loading branch information
victormlg committed Jan 24, 2025
1 parent 3a20f85 commit 86c1d97
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 21 deletions.
54 changes: 34 additions & 20 deletions cf_remote/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
from collections import OrderedDict

from cf_remote.utils import (
error_and_none,
os_release,
column_print,
parse_envfile,
pretty,
programmer_error,
user_error,
parse_systeminfo,
parse_version,
Expand Down Expand Up @@ -205,38 +208,49 @@ def get_info(host, *, users=None, connection=None):
data["agent_version"] = parse_version(ssh_cmd(connection, version_cmd))
else:
data["os"] = "unix"
data["uname"] = ssh_cmd(connection, "uname")
data["arch"] = ssh_cmd(connection, "uname -m")
data["os_release"] = os_release(ssh_cmd(connection, "cat /etc/os-release"))

scp("nt-discovery.sh", host, connection)
discovery = parse_envfile(ssh_sudo(connection, "bash nt-discovery.sh"))

if discovery is None:
programmer_error("Couldn't parse NT discovery file")

data["uname"] = (
discovery.get("NTD_UNAME")
if discovery.get("NTD_UNAME")
else error_and_none(discovery.get("NTD_UNAME_ERROR"))
)
data["arch"] = (
discovery.get("NTD_ARCH")
if discovery.get("NTD_ARCH")
else error_and_none(discovery.get("NTD_ARCH_ERROR"))
)
data["os_release"] = (
os_release(discovery.get("NTD_OS_RELEASE"))
if discovery.get("NTD_OS_RELEASE")
else error_and_none(discovery.get("NTD_OS_RELEASE_ERROR"))
)

os_release_data = data.get("os_release")
redhat_release_data = None
if not os_release_data:
redhat_release_data = ssh_cmd(connection, "cat /etc/redhat-release")
redhat_release_data = (
discovery.get("NTD_REDHAT_RELEASE")
if discovery.get("NTD_REDHAT_RELEASE")
else error_and_none(discovery.get("NTD_REDHAT_RELEASE_ERROR"))
)
data["redhat_release"] = redhat_release_data

data["package_tags"] = get_package_tags(os_release_data, redhat_release_data)

data["agent_location"] = ssh_cmd(connection, "command -v cf-agent")
data["policy_server"] = ssh_cmd(
connection, "cat /var/cfengine/policy_server.dat"
)
if user != "root" and not data["policy_server"]:
# If we are not SSHing as root and we failed to read
# the policy_server.dat file try again using sudo:
data["policy_server"] = ssh_sudo(
connection, "cat /var/cfengine/policy_server.dat"
)

data["agent_location"] = discovery.get("NTD_CFAGENT_PATH")
data["policy_server"] = discovery.get("NTD_POLICY_SERVER")
agent = r"/var/cfengine/bin/cf-agent"
data["agent"] = agent
data["agent_version"] = parse_version(
ssh_cmd(connection, "{} --version".format(agent))
)
data["agent_version"] = parse_version(discovery.get("NTD_CFAGENT_VERSION"))

data["bin"] = {}
for bin in ["dpkg", "rpm", "yum", "apt", "pkg", "zypper"]:
path = ssh_cmd(connection, "command -v {}".format(bin))
path = discovery.get("NTD_{}".format(bin.upper()))
if path:
data["bin"][bin] = path

Expand Down
57 changes: 57 additions & 0 deletions cf_remote/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,60 @@ def is_different_checksum(checksum, content):

digest = hashlib.sha256(content).digest().hex()
return checksum != digest


def error_and_none(msg):
log.error(msg)
return None


def parse_envfile(text):

if not text:
return error_and_none("Missing env file")

data = OrderedDict()
lines = text.splitlines()
for line in lines:
if line.strip() == "":
return error_and_none(
"Invalid env file format: Empty or whitespace only line"
)

if "=" not in line:
return error_and_none("Invalid env file format: '=' missing")

key, _, val = line.partition("=")

if not key:
return error_and_none("Invalid env file format: Key missing")

if not re.fullmatch(r"([A-Z]+\_?)+", key):
return error_and_none("Invalid env file format: Invalid key")

if not (val.startswith('"') and val.endswith('"')):
return error_and_none(
"Invalid env file format: value must start and end with double quotes"
)

val = val[1:-1] # Remove double quotes on each side

if has_unescaped_character(val, '"'):
return error_and_none("Invalid env file format: quotes not escaped")

data[key] = val.encode("utf-8").decode("unicode_escape")

return data


def has_unescaped_character(string, char):
previous = None
for current in string:
if current == char and previous != "\\":
return True
previous = current
return False


def programmer_error(msg):
sys.exit("Programmer error: " + msg)
54 changes: 54 additions & 0 deletions nt-discovery.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/bash

set -o pipefail

run_command() {
# $1: command to run
# $2: variable name to store in / output
# $3: custom error message (optional)
result="$(bash -c "$1" 2>&1 | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' | sed -e 's/\"/\\"/g')"
status=$?
if [ "$status" -eq "0" ]; then
echo "NTD_$2=\"$result\""
else
echo "NTD_$2_CMD=\"$1\""
# custom output result
if [ "$#" -eq "3" ]; then
echo "NTD_$2_ERROR=\"$3\""
else
echo "NTD_$2_ERROR=\"$result\""
fi
fi
}

run_command "uname" "UNAME"
run_command "uname -m" "ARCH"
run_command "cat /etc/os-release" "OS_RELEASE"
run_command "cat /etc/redhat-release" "REDHAT_RELEASE"

# cf-agent

cfagent_path=$(command -v cf-agent)

if ! [ $? -eq "0" ]; then
cfagent_path=$(command -v /var/cfengine/bin/cf-agent)

if ! [ $? -eq "0" ]; then
cfagent_path="cf-agent"
fi
fi

run_command "command -v $cfagent_path" "CFAGENT_PATH" "Cannot find cf-agent"
run_command "$cfagent_path --version" "CFAGENT_VERSION"
run_command "cat /var/cfengine/policy_server.dat" "POLICY_SERVER"

# packages

run_command "echo $UID" "UID"
run_command "command -v dpkg" "DPKG" "Cannot find dpkg"
run_command "command -v rpm" "RPM" "Cannot find rpm"
run_command "command -v yum" "YUM" "Cannot find yum"
run_command "command -v apt" "APT" "Cannot find apt"
run_command "command -v pkg" "PKG" "Cannot find pkg"
run_command "command -v zypper" "ZYPPER" "Cannot find zypper"

2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# pip has gotten strict with version numbers
# so change it to: "1.3.3+22.git.gdf81228"
# See: https://peps.python.org/pep-0440/#local-version-segments
v,i,s = cf_remote_version.split("-")
v, i, s = cf_remote_version.split("-")
cf_remote_version = v + "+" + i + ".git." + s

assert "-" not in cf_remote_version
Expand Down
47 changes: 47 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from cf_remote.utils import has_unescaped_character, parse_envfile


def test_parse_envfile():
data = parse_envfile('NTD_TEST="test"')
assert "NTD_TEST" in data
assert data["NTD_TEST"] == "test"

data = parse_envfile('NTD_TEST="\\"helloworld\\""')
assert data["NTD_TEST"] == '"helloworld"'

data = parse_envfile('NTD_TEST=""helloworld""')
assert data is None

data = parse_envfile('NTD_TEST="\n"')
assert data is None

data = parse_envfile('NTD_TEST="\\nhello"')
assert data["NTD_TEST"] == "\nhello"

# 2 lines:
data = parse_envfile('NTD_TEST="test"\nNTD_HELLO="hello"')
assert len(data) == 2
assert data["NTD_TEST"] == "test"
assert data["NTD_HELLO"] == "hello"
# Empty value is allowed:
data = parse_envfile('NTD_EMPTY=""')
assert data["NTD_EMPTY"] == ""
# Empty key is not allowed:
assert parse_envfile('="value"') is None
# Lowercase key not allowed:
assert parse_envfile('NTD_key="value"') is None
# Various cases of things which are not allowed:
assert parse_envfile('') is None
assert parse_envfile('=') is None
assert parse_envfile('""=""') is None
assert parse_envfile('=""') is None
assert parse_envfile('""=') is None
assert parse_envfile(' ') is None
assert parse_envfile('NTD_TEST="NTD_TEST_TWO="test"\\nhello"') is None


def test_has_unescaped_character():
assert not has_unescaped_character(r"test", '"')
assert not has_unescaped_character(r"\"test\"", '"')
assert has_unescaped_character(r'hello"world', '"')
assert has_unescaped_character(r'hello\""world', '"')

0 comments on commit 86c1d97

Please sign in to comment.