1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
# Copyright (C) 2011 Canonical Ltd.
# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P.
#
# Author: Scott Moser <scott.moser@canonical.com>
# Author: Juerg Haefliger <juerg.haefliger@hp.com>
#
# This file is part of cloud-init. See LICENSE file for license information.
"""Phone Home: Post data to url"""
import logging
from cloudinit import templater, url_helper, util
from cloudinit.cloud import Cloud
from cloudinit.config import Config
from cloudinit.config.schema import MetaSchema
from cloudinit.distros import ALL_DISTROS
from cloudinit.settings import PER_INSTANCE
POST_LIST_ALL = [
"pub_key_rsa",
"pub_key_ecdsa",
"pub_key_ed25519",
"instance_id",
"hostname",
"fqdn",
]
meta: MetaSchema = {
"id": "cc_phone_home",
"distros": [ALL_DISTROS],
"frequency": PER_INSTANCE,
"activate_by_schema_keys": ["phone_home"],
}
LOG = logging.getLogger(__name__)
# phone_home:
# url: http://my.foo.bar/{{ v1.instance_id }}/
# post: all
# tries: 10
#
# phone_home:
# url: http://my.foo.bar/{{ v1.instance_id }}/
# post: [ pub_key_rsa, pub_key_ecdsa, instance_id, hostname,
# fqdn ]
#
def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None:
if args:
ph_cfg = util.read_conf(args[0])
else:
if "phone_home" not in cfg:
LOG.debug(
"Skipping module named %s, "
"no 'phone_home' configuration found",
name,
)
return
ph_cfg = cfg["phone_home"]
if "url" not in ph_cfg:
LOG.warning(
"Skipping module named %s, "
"no 'url' found in 'phone_home' configuration",
name,
)
return
url = ph_cfg["url"]
post_list = ph_cfg.get("post", "all")
tries = ph_cfg.get("tries")
try:
tries = int(tries) # type: ignore
except (ValueError, TypeError):
tries = 10
util.logexc(
LOG,
"Configuration entry 'tries' is not an integer, using %s instead",
tries,
)
if post_list == "all":
post_list = POST_LIST_ALL
all_keys = {
"instance_id": cloud.get_instance_id(),
"hostname": cloud.get_hostname().hostname,
"fqdn": cloud.get_hostname(fqdn=True).hostname,
}
pubkeys = {
"pub_key_rsa": "/etc/ssh/ssh_host_rsa_key.pub",
"pub_key_ecdsa": "/etc/ssh/ssh_host_ecdsa_key.pub",
"pub_key_ed25519": "/etc/ssh/ssh_host_ed25519_key.pub",
}
for n, path in pubkeys.items():
try:
all_keys[n] = util.load_text_file(path)
except Exception:
util.logexc(
LOG, "%s: failed to open, can not phone home that data!", path
)
submit_keys = {}
for k in post_list:
if k in all_keys:
submit_keys[k] = all_keys[k]
else:
submit_keys[k] = None
LOG.warning(
"Requested key %s from 'post'"
" configuration list not available",
k,
)
# Get them read to be posted
real_submit_keys = {}
for k, v in submit_keys.items():
if v is None:
real_submit_keys[k] = "N/A"
else:
real_submit_keys[k] = str(v)
# Incase the url is parameterized
url_params = {
"INSTANCE_ID": all_keys["instance_id"],
}
url = templater.render_string(url, url_params)
try:
url_helper.read_file_or_url(
url,
data=real_submit_keys,
retries=tries - 1,
sec_between=3,
ssl_details=util.fetch_ssl_details(cloud.paths),
)
except Exception:
util.logexc(
LOG, "Failed to post phone home data to %s in %s tries", url, tries
)
|