10
10
11
11
from pycloudlib .errors import PycloudlibError
12
12
from pycloudlib .instance import BaseInstance
13
- from pycloudlib .oci .utils import get_subnet_id , get_subnet_id_by_name , wait_till_ready
13
+ from pycloudlib .oci .utils import (
14
+ generate_create_vnic_details ,
15
+ get_subnet_id ,
16
+ get_subnet_id_by_name ,
17
+ wait_till_ready ,
18
+ )
19
+ from pycloudlib .types import NetworkingConfig
14
20
15
21
16
22
class OciInstance (BaseInstance ):
@@ -27,6 +33,7 @@ def __init__(
27
33
oci_config = None ,
28
34
* ,
29
35
username : Optional [str ] = None ,
36
+ vcn_name : Optional [str ] = None ,
30
37
):
31
38
"""Set up the instance.
32
39
@@ -46,6 +53,7 @@ def __init__(
46
53
self .availability_domain = availability_domain
47
54
self ._fault_domain = None
48
55
self ._ip = None
56
+ self ._vcn_name : Optional [str ] = vcn_name
49
57
50
58
if oci_config is None :
51
59
oci_config = oci .config .from_file ("~/.oci/config" ) # noqa: E501
@@ -145,7 +153,8 @@ def secondary_vnic_private_ip(self) -> Optional[str]:
145
153
for vnic_attachment in vnic_attachments
146
154
]
147
155
secondary_vnic_attachment = [vnic for vnic in vnics if not vnic .is_primary ][0 ]
148
- return secondary_vnic_attachment .private_ip
156
+ self ._log .debug ("secondary vnic attachment data:\n %s" , secondary_vnic_attachment )
157
+ return secondary_vnic_attachment .private_ip or secondary_vnic_attachment .ipv6_addresses [0 ]
149
158
150
159
@property
151
160
def instance_data (self ):
@@ -258,7 +267,7 @@ def get_secondary_vnic_ip(self) -> str:
258
267
def add_network_interface (
259
268
self ,
260
269
nic_index : int = 0 ,
261
- use_private_subnet : bool = False ,
270
+ networking_config : Optional [ NetworkingConfig ] = None ,
262
271
subnet_name : Optional [str ] = None ,
263
272
** kwargs : Any ,
264
273
) -> str :
@@ -270,13 +279,19 @@ def add_network_interface(
270
279
271
280
Args:
272
281
nic_index: The index of the NIC to add
273
- subnet_name: Name of the subnet to add the NIC to. If not provided,
274
- will use `use_private_subnet` to select first available subnet.
275
- use_private_subnet: If True, will select the first available private
276
- subnet. If False, will select the first available public subnet.
277
- This is only used if `subnet_name` is not provided.
282
+ networking_config: Networking configuration to use when selecting subnet. This specifies
283
+ the networking type (ipv4, ipv6, or dualstack) and whether to use a public or
284
+ private subnet. If not provided, will default to selecting the first public subnet
285
+ found.
286
+ subnet_name: Name of the subnet to add the NIC to. If provided, this subnet will
287
+ blindly be selected and networking_config will be ignored.
288
+
289
+ Returns:
290
+ str: The private IP address of the added network interface.
278
291
"""
279
292
if subnet_name :
293
+ if networking_config :
294
+ self ._log .debug ("Ignoring networking_config when subnet_name is provided." )
280
295
subnet_id = get_subnet_id_by_name (
281
296
self .network_client ,
282
297
self .compartment_id ,
@@ -287,10 +302,11 @@ def add_network_interface(
287
302
self .network_client ,
288
303
self .compartment_id ,
289
304
self .availability_domain ,
290
- private = use_private_subnet ,
305
+ networking_config = networking_config ,
306
+ vcn_name = self ._vcn_name ,
291
307
)
292
- create_vnic_details = oci . core . models . CreateVnicDetails ( # noqa: E501
293
- subnet_id = subnet_id ,
308
+ create_vnic_details = generate_create_vnic_details (
309
+ subnet_id = subnet_id , networking_config = networking_config
294
310
)
295
311
attach_vnic_details = oci .core .models .AttachVnicDetails ( # noqa: E501
296
312
create_vnic_details = create_vnic_details ,
@@ -304,13 +320,29 @@ def add_network_interface(
304
320
desired_state = vnic_attachment_data .LIFECYCLE_STATE_ATTACHED ,
305
321
)
306
322
vnic_data = self .network_client .get_vnic (vnic_attachment_data .vnic_id ).data
323
+ self ._log .debug (
324
+ "Newly attached vnic data:\n %s" ,
325
+ vnic_data ,
326
+ )
327
+ try :
328
+ new_ip = vnic_data .private_ip or vnic_data .ipv6_addresses [0 ]
329
+ except IndexError :
330
+ err_msg = (
331
+ "Unexpected error occurred when trying to retrieve local IP address of the "
332
+ "newly attached NIC. No private IP or IPv6 address found."
333
+ )
334
+ self ._log .error (
335
+ err_msg + "Full vnic data for debugging purposes:\n %s" ,
336
+ vnic_data ,
337
+ )
338
+ raise PycloudlibError (err_msg )
307
339
self ._log .info (
308
- "Added network interface with private IP %s to instance %s on nic #%s" ,
309
- vnic_data . private_ip ,
340
+ "Added network interface with IP %s to instance %s on nic #%s" ,
341
+ new_ip ,
310
342
self .instance_id ,
311
343
nic_index ,
312
344
)
313
- return vnic_data . private_ip
345
+ return new_ip
314
346
315
347
def remove_network_interface (self , ip_address : str ):
316
348
"""Remove network interface based on IP address.
@@ -355,14 +387,20 @@ def configure_secondary_vnic(self) -> str:
355
387
or if the IP address was not successfully assigned to the interface.
356
388
PycloudlibError: If failed to fetch secondary VNIC data from the Oracle Cloud metadata service.
357
389
"""
358
- if not self .secondary_vnic_private_ip :
390
+ secondary_ip = self .secondary_vnic_private_ip
391
+ if not secondary_ip :
359
392
raise ValueError ("Cannot configure secondary VNIC without a secondary VNIC attached" )
393
+ if ":" in secondary_ip :
394
+ imds_url = "http://[fd00:c1::a9fe:a9fe]/opc/v1/vnics"
395
+ else :
396
+ imds_url = "http://169.254.169.254/opc/v1/vnics"
397
+
360
398
secondary_vnic_imds_data : Optional [Dict [str , str ]] = None
361
399
# it can take a bit for the secondary VNIC to show up in the IMDS
362
400
# so we need to retry fetching the data for roughly a minute
363
401
for _ in range (60 ):
364
402
# Fetch JSON data from the Oracle Cloud metadata service
365
- imds_req = self .execute ("curl -s http://169.254.169.254/opc/v1/vnics " ).stdout
403
+ imds_req = self .execute (f "curl -s { imds_url } " ).stdout
366
404
vnics_data = json .loads (imds_req )
367
405
if len (vnics_data ) > 1 :
368
406
self ._log .debug ("Successfully fetched secondary VNIC data from IMDS" )
0 commit comments