2020import re
2121import shlex
2222import textwrap
23+ from typing import Any , Dict , List , Optional , overload
2324
2425from cloudinit import atomic_helper , net , sources , subp , util
2526
@@ -56,8 +57,8 @@ def __str__(self):
5657
5758 def _get_data (self ):
5859 defaults = {"instance-id" : DEFAULT_IID }
59- results = None
60- seed = None
60+ results : Optional [ Dict [ str , Any ]] = None
61+ seed : Optional [ str ] = None
6162
6263 # decide parseuser for context.sh shell reader
6364 parseuser = DEFAULT_PARSEUSER
@@ -94,7 +95,7 @@ def _get_data(self):
9495 LOG .debug ("found datasource in %s" , cdev )
9596 break
9697
97- if not seed :
98+ if not seed or results is None :
9899 return False
99100
100101 # merge fetched metadata with datasource defaults
@@ -115,8 +116,10 @@ def _get_data(self):
115116 self .userdata_raw = results .get ("userdata" )
116117 return True
117118
118- def _get_subplatform (self ):
119+ def _get_subplatform (self ) -> str :
119120 """Return the subplatform metadata source details."""
121+ if self .seed is None :
122+ return sources .METADATA_UNKNOWN
120123 if self .seed_dir in self .seed :
121124 subplatform_type = "seed-dir"
122125 else :
@@ -148,33 +151,40 @@ class BrokenContextDiskDir(Exception):
148151
149152
150153class OpenNebulaNetwork :
151- def __init__ (self , context , distro , system_nics_by_mac = None ):
154+ def __init__ (
155+ self ,
156+ context : Dict [str , str ],
157+ distro : Any ,
158+ system_nics_by_mac : Optional [Dict [str , str ]] = None ,
159+ ) -> None :
152160 self .context = context
153161 if system_nics_by_mac is None :
154162 system_nics_by_mac = get_physical_nics_by_mac (distro )
155- self .ifaces = collections .OrderedDict (
156- [
157- k
158- for k in sorted (
159- system_nics_by_mac .items (),
160- key = lambda k : net .natural_sort_key (k [1 ]),
161- )
162- ]
163+ self .ifaces : collections .OrderedDict [str , str ] = (
164+ collections .OrderedDict (
165+ [
166+ k
167+ for k in sorted (
168+ system_nics_by_mac .items (),
169+ key = lambda k : net .natural_sort_key (k [1 ]),
170+ )
171+ ]
172+ )
163173 )
164174
165175 # OpenNebula 4.14+ provide macaddr for ETHX in variable ETH_MAC.
166176 # context_devname provides {mac.lower():ETHX, mac2.lower():ETHX}
167- self .context_devname = {}
177+ self .context_devname : Dict [ str , str ] = {}
168178 for k , v in context .items ():
169179 m = re .match (r"^(.+)_MAC$" , k )
170180 if m :
171181 self .context_devname [v .lower ()] = m .group (1 )
172182
173- def mac2ip (self , mac ) :
183+ def mac2ip (self , mac : str ) -> str :
174184 return "." .join ([str (int (c , 16 )) for c in mac .split (":" )[2 :]])
175185
176- def get_nameservers (self , dev ) :
177- nameservers = {}
186+ def get_nameservers (self , dev : str ) -> Dict [ str , List [ str ]] :
187+ nameservers : Dict [ str , List [ str ]] = {}
178188 dns = self .get_field (dev , "dns" , "" ).split ()
179189 dns .extend (self .context .get ("DNS" , "" ).split ())
180190 if dns :
@@ -184,14 +194,14 @@ def get_nameservers(self, dev):
184194 nameservers ["search" ] = search_domain
185195 return nameservers
186196
187- def get_mtu (self , dev ) :
197+ def get_mtu (self , dev : str ) -> Optional [ str ] :
188198 return self .get_field (dev , "mtu" )
189199
190- def get_ip (self , dev , mac ) :
200+ def get_ip (self , dev : str , mac : str ) -> str :
191201 return self .get_field (dev , "ip" , self .mac2ip (mac ))
192202
193- def get_ip6 (self , dev ) :
194- addresses6 = []
203+ def get_ip6 (self , dev : str ) -> List [ str ] :
204+ addresses6 : List [ str ] = []
195205 ip6 = self .get_field (dev , "ip6" )
196206 if ip6 :
197207 addresses6 .append (ip6 )
@@ -200,24 +210,35 @@ def get_ip6(self, dev):
200210 addresses6 .append (ip6_ula )
201211 return addresses6
202212
203- def get_ip6_prefix (self , dev ) :
213+ def get_ip6_prefix (self , dev : str ) -> str :
204214 return self .get_field (dev , "ip6_prefix_length" , "64" )
205215
206- def get_gateway (self , dev ) :
216+ def get_gateway (self , dev : str ) -> Optional [ str ] :
207217 return self .get_field (dev , "gateway" )
208218
209- def get_gateway6 (self , dev ) :
219+ def get_gateway6 (self , dev : str ) -> Optional [ str ] :
210220 # OpenNebula 6.1.80 introduced new context parameter ETHx_IP6_GATEWAY
211221 # to replace old ETHx_GATEWAY6. Old ETHx_GATEWAY6 will be removed in
212222 # OpenNebula 6.4.0 (https://github.com/OpenNebula/one/issues/5536).
213- return self .get_field (
214- dev , "ip6_gateway" , self .get_field (dev , "gateway6" )
215- )
223+ ip6_gateway = self .get_field (dev , "ip6_gateway" )
224+ if ip6_gateway is not None :
225+ return ip6_gateway
226+ return self .get_field (dev , "gateway6" )
216227
217- def get_mask (self , dev ) :
228+ def get_mask (self , dev : str ) -> str :
218229 return self .get_field (dev , "mask" , "255.255.255.0" )
219230
220- def get_field (self , dev , name , default = None ):
231+ @overload
232+ def get_field (self , dev : str , name : str ) -> Optional [str ]: ...
233+ @overload
234+ def get_field (
235+ self , dev : str , name : str , default : None
236+ ) -> Optional [str ]: ...
237+ @overload
238+ def get_field (self , dev : str , name : str , default : str ) -> str : ...
239+ def get_field (
240+ self , dev : str , name : str , default : Optional [str ] = None
241+ ) -> Optional [str ]:
221242 """return the field name in context for device dev.
222243
223244 context stores <dev>_<NAME> (example: eth0_DOMAIN).
@@ -233,20 +254,18 @@ def get_field(self, dev, name, default=None):
233254 # allow empty string to return the default.
234255 return default if val in (None , "" ) else val
235256
236- def gen_conf (self ):
237- netconf = {}
238- netconf ["version" ] = 2
239- netconf ["ethernets" ] = {}
257+ def gen_conf (self ) -> Dict [str , Any ]:
258+ netconf : Dict [str , Any ] = {"version" : 2 , "ethernets" : {}}
240259
241- ethernets = {}
260+ ethernets : Dict [ str , Dict [ str , Any ]] = {}
242261 for mac , dev in self .ifaces .items ():
243262 mac = mac .lower ()
244263
245264 # c_dev stores name in context 'ETHX' for this device.
246265 # dev stores the current system name.
247266 c_dev = self .context_devname .get (mac , dev )
248267
249- devconf = {}
268+ devconf : Dict [ str , Any ] = {}
250269
251270 # Set MAC address
252271 devconf ["match" ] = {"macaddress" : mac }
@@ -323,7 +342,9 @@ def varprinter():
323342 )
324343
325344
326- def parse_shell_config (content , asuser = None ):
345+ def parse_shell_config (
346+ content : str , asuser : Optional [str ] = None
347+ ) -> Dict [str , str ]:
327348 """run content and return environment variables which changed
328349
329350 WARNING: the special variable _start_ is used to delimit content
@@ -394,13 +415,19 @@ def parse_shell_config(content, asuser=None):
394415 return ret
395416
396417
397- def read_context_disk_dir (source_dir , distro , asuser = None ):
398- """
399- read_context_disk_dir(source_dir):
400- read source_dir and return a tuple with metadata dict and user-data
401- string populated. If not a valid dir, raise a NonContextDiskDir
418+ def read_context_disk_dir (
419+ source_dir : str , distro : Any , asuser : Optional [str ] = None
420+ ) -> Dict [str , Any ]:
421+ """Read ``source_dir`` and return a dictionary containing context data.
422+
423+ The returned dictionary always includes ``"metadata"`` and
424+ ``"userdata"`` keys, and may also include ``"network-interfaces"``
425+ when network configuration can be generated from the context.
426+
427+ If ``source_dir`` is not a valid context directory, raise
428+ ``NonContextDiskDir``.
402429 """
403- found = {}
430+ found : Dict [ str , str ] = {}
404431 for af in CONTEXT_DISK_FILES :
405432 fn = os .path .join (source_dir , af )
406433 if os .path .isfile (fn ):
@@ -409,8 +436,8 @@ def read_context_disk_dir(source_dir, distro, asuser=None):
409436 if not found :
410437 raise NonContextDiskDir ("%s: %s" % (source_dir , "no files found" ))
411438
412- context = {}
413- results = {"userdata" : None , "metadata" : {}}
439+ context : Dict [ str , str ] = {}
440+ results : Dict [ str , Any ] = {"userdata" : None , "metadata" : {}}
414441
415442 if "context.sh" in found :
416443 if asuser is not None :
@@ -450,7 +477,7 @@ def read_context_disk_dir(source_dir, distro, asuser=None):
450477 ssh_key_var = "SSH_PUBLIC_KEY"
451478
452479 if ssh_key_var :
453- lines = context . get ( ssh_key_var ) .splitlines ()
480+ lines = context [ ssh_key_var ] .splitlines ()
454481 results ["metadata" ]["public-keys" ] = [
455482 line for line in lines if len (line ) and not line .startswith ("#" )
456483 ]
@@ -490,7 +517,7 @@ def read_context_disk_dir(source_dir, distro, asuser=None):
490517 return results
491518
492519
493- def get_physical_nics_by_mac (distro ) :
520+ def get_physical_nics_by_mac (distro : Any ) -> Dict [ str , str ] :
494521 devs = net .get_interfaces_by_mac ()
495522 return dict (
496523 [(m , n ) for m , n in devs .items () if distro .networking .is_physical (n )]
0 commit comments