blob: 427395a451111bf92ce2327768c1f3d252670c86 [file] [log] [blame]
Zack Williamscaf05662020-10-09 19:52:40 -07001#!/usr/bin/env python3
2
3# SPDX-FileCopyrightText: © 2020 Open Networking Foundation <support@opennetworking.org>
4# SPDX-License-Identifier: Apache-2.0
5
6from __future__ import absolute_import
7
8import argparse
9import json
10import logging
11import netaddr
12import re
13import ssl
14import urllib.parse
15import urllib.request
16from ruamel import yaml
17
18# create shared logger
19logging.basicConfig()
20logger = logging.getLogger("nbht")
21
22# headers to pass, set globally
23headers = []
24
25# settings
26settings = {}
27
28def parse_nb_args():
29 """
30 parse CLI arguments
31 """
32
33 parser = argparse.ArgumentParser(description="NetBox Host Descriptions")
34
35 # Positional args
36 parser.add_argument(
37 "settings",
38 type=argparse.FileType("r"),
39 help="YAML ansible inventory file w/netbox info",
40 )
41
42 parser.add_argument(
43 "--debug", action="store_true", help="Print additional debugging information"
44 )
45
46 return parser.parse_args()
47
48
49def json_api_get(
50 url,
51 headers,
52 data=None,
53 trim_prefix=False,
54 allow_failure=False,
55 validate_certs=False,
56):
57 """
58 Call JSON API endpoint, return data as a dict
59 """
60
61 logger.debug("json_api_get url: %s", url)
62
63 # if data included, encode it as JSON
64 if data:
65 data_enc = str(json.dumps(data)).encode("utf-8")
66
67 request = urllib.request.Request(url, data=data_enc, method="POST")
68 request.add_header("Content-Type", "application/json; charset=UTF-8")
69 else:
70 request = urllib.request.Request(url)
71
72 # add headers tuples
73 for header in headers:
74 request.add_header(*header)
75
76 try:
77
78 if validate_certs:
79 response = urllib.request.urlopen(request)
80
81 else:
82 ctx = ssl.create_default_context()
83 ctx.check_hostname = False
84 ctx.verify_mode = ssl.CERT_NONE
85
86 response = urllib.request.urlopen(request, context=ctx)
87
88 except urllib.error.HTTPError:
89 # asking for data that doesn't exist results in a 404, just return nothing
90 if allow_failure:
91 return None
92 logger.exception("Server encountered an HTTPError at URL: '%s'", url)
93 except urllib.error.URLError:
94 logger.exception("An URLError occurred at URL: '%s'", url)
95 else:
96 # docs: https://docs.python.org/3/library/json.html
97 jsondata = response.read()
98 logger.debug("API response: %s", jsondata)
99
100 try:
101 data = json.loads(jsondata)
102 except json.decoder.JSONDecodeError:
103 # allow return of no data
104 if allow_failure:
105 return None
106 logger.exception("Unable to decode JSON")
107 else:
108 logger.debug("JSON decoded: %s", data)
109
110 return data
111
112
113def get_pxe_devices(tenant_group, filters=""):
114
115 # get all devices in a prefix
116 url = "%s%s" % (
117 settings["api_endpoint"],
118 "api/dcim/devices/?tenant_group=%s%s" % (tenant_group, filters),
119 )
120
121 print(url)
122
123 raw_devs = json_api_get(url, headers, validate_certs=settings["validate_certs"])
124
125 logger.debug("raw_devs: %s", raw_devs)
126
127 devs = []
128
129 for item in raw_devs["results"]:
130 dev = {}
131 dev["serial"] = item["serial"]
132 dev["hostname"] = item["name"]
133 dev["domain"] = "aetherproject.net"
134
135 devs.append(dev)
136
137 return devs
138
139
140# main function that calls other functions
141if __name__ == "__main__":
142
143 args = parse_nb_args()
144
145 # only print log messages if debugging
146 if args.debug:
147 logger.setLevel(logging.DEBUG)
148 else:
149 logger.setLevel(logging.INFO)
150
151 # load settings from yaml file
152 settings = yaml.safe_load(args.settings.read())
153
154 logger.info("settings: %s" % settings)
155
156 # global, so this isn't run multiple times
157 headers = [
158 ("Authorization", "Token %s" % settings["token"]),
159 ]
160
161 # create structure from extracted data
162
163 pxe_devices = get_pxe_devices("aether", "&role_id=1")
164
165 print(yaml.safe_dump({"pxeboot_hosts": pxe_devices}, indent=2))