@@ -44,6 +44,10 @@ type Driver struct {
44
44
UsePrivateNetwork bool
45
45
DisablePublic4 bool
46
46
DisablePublic6 bool
47
+ PrimaryIPv4 string
48
+ cachedPrimaryIPv4 * hcloud.PrimaryIP
49
+ PrimaryIPv6 string
50
+ cachedPrimaryIPv6 * hcloud.PrimaryIP
47
51
Firewalls []string
48
52
ServerLabels map [string ]string
49
53
keyLabels map [string ]string
@@ -72,6 +76,8 @@ const (
72
76
flagUsePrivateNetwork = "hetzner-use-private-network"
73
77
flagDisablePublic4 = "hetzner-disable-public-4"
74
78
flagDisablePublic6 = "hetzner-disable-public-6"
79
+ flagPrimary4 = "hetzner-primary-ipv4"
80
+ flagPrimary6 = "hetzner-primary-ipv6"
75
81
flagDisablePublic = "hetzner-disable-public"
76
82
flagFirewalls = "hetzner-firewalls"
77
83
flagAdditionalKeys = "hetzner-additional-key"
@@ -189,6 +195,18 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
189
195
Name : flagDisablePublic ,
190
196
Usage : "Disable public ip (v4 & v6)" ,
191
197
},
198
+ mcnflag.StringFlag {
199
+ EnvVar : "HETZNER_PRIMARY_IPV4" ,
200
+ Name : flagPrimary4 ,
201
+ Usage : "Existing primary IPv4 address" ,
202
+ Value : "" ,
203
+ },
204
+ mcnflag.StringFlag {
205
+ EnvVar : "HETZNER_PRIMARY_IPV6" ,
206
+ Name : flagPrimary6 ,
207
+ Usage : "Existing primary IPv6 address" ,
208
+ Value : "" ,
209
+ },
192
210
mcnflag.StringSliceFlag {
193
211
EnvVar : "HETZNER_FIREWALLS" ,
194
212
Name : flagFirewalls ,
@@ -261,6 +279,8 @@ func (d *Driver) setConfigFromFlagsImpl(opts drivers.DriverOptions) error {
261
279
d .UsePrivateNetwork = opts .Bool (flagUsePrivateNetwork ) || disablePublic
262
280
d .DisablePublic4 = opts .Bool (flagDisablePublic4 ) || disablePublic
263
281
d .DisablePublic6 = opts .Bool (flagDisablePublic6 ) || disablePublic
282
+ d .PrimaryIPv4 = opts .String (flagPrimary4 )
283
+ d .PrimaryIPv6 = opts .String (flagPrimary6 )
264
284
d .Firewalls = opts .StringSlice (flagFirewalls )
265
285
d .AdditionalKeys = opts .StringSlice (flagAdditionalKeys )
266
286
@@ -297,6 +317,14 @@ func (d *Driver) setConfigFromFlagsImpl(opts drivers.DriverOptions) error {
297
317
flagUsePrivateNetwork , flagDisablePublic )
298
318
}
299
319
320
+ if d .DisablePublic4 && d .PrimaryIPv4 != "" {
321
+ return d .flagFailure ("--%v and --%v are mutually exclusive" , flagPrimary4 , flagDisablePublic4 )
322
+ }
323
+
324
+ if d .DisablePublic6 && d .PrimaryIPv6 != "" {
325
+ return d .flagFailure ("--%v and --%v are mutually exclusive" , flagPrimary6 , flagDisablePublic6 )
326
+ }
327
+
300
328
return nil
301
329
}
302
330
@@ -375,6 +403,14 @@ func (d *Driver) PreCreateCheck() error {
375
403
return fmt .Errorf ("could not create placement group: %w" , err )
376
404
}
377
405
406
+ if _ , err := d .getPrimaryIPv4 (); err != nil {
407
+ return fmt .Errorf ("could not resolve primary IPv4: %w" , err )
408
+ }
409
+
410
+ if _ , err := d .getPrimaryIPv6 (); err != nil {
411
+ return fmt .Errorf ("could not resolve primary IPv6: %w" , err )
412
+ }
413
+
378
414
if d .UsePrivateNetwork && len (d .Networks ) == 0 {
379
415
return errors .Errorf ("No private network attached." )
380
416
}
@@ -495,11 +531,9 @@ func (d *Driver) makeCreateServerOptions() (*hcloud.ServerCreateOpts, error) {
495
531
PlacementGroup : pgrp ,
496
532
}
497
533
498
- if d .DisablePublic4 || d .DisablePublic6 {
499
- srvopts .PublicNet = & hcloud.ServerCreatePublicNet {
500
- EnableIPv4 : ! d .DisablePublic4 ,
501
- EnableIPv6 : ! d .DisablePublic6 ,
502
- }
534
+ err = d .setPublicNetIfRequired (srvopts )
535
+ if err != nil {
536
+ return nil , err
503
537
}
504
538
505
539
networks , err := d .createNetworks ()
@@ -537,6 +571,27 @@ func (d *Driver) makeCreateServerOptions() (*hcloud.ServerCreateOpts, error) {
537
571
return & srvopts , nil
538
572
}
539
573
574
+ func (d * Driver ) setPublicNetIfRequired (srvopts hcloud.ServerCreateOpts ) error {
575
+ pip4 , err := d .getPrimaryIPv4 ()
576
+ if err != nil {
577
+ return err
578
+ }
579
+ pip6 , err := d .getPrimaryIPv6 ()
580
+ if err != nil {
581
+ return err
582
+ }
583
+
584
+ if d .DisablePublic4 || d .DisablePublic6 || pip4 != nil || pip6 != nil {
585
+ srvopts .PublicNet = & hcloud.ServerCreatePublicNet {
586
+ EnableIPv4 : ! d .DisablePublic4 ,
587
+ EnableIPv6 : ! d .DisablePublic6 ,
588
+ IPv4 : pip4 ,
589
+ IPv6 : pip6 ,
590
+ }
591
+ }
592
+ return nil
593
+ }
594
+
540
595
func (d * Driver ) createNetworks () ([]* hcloud.Network , error ) {
541
596
networks := []* hcloud.Network {}
542
597
for _ , networkIDorName := range d .Networks {
@@ -1094,3 +1149,52 @@ func (d *Driver) removeEmptyServerPlacementGroup(srv *hcloud.Server) error {
1094
1149
return nil
1095
1150
}
1096
1151
}
1152
+
1153
+ func (d * Driver ) getPrimaryIPv4 () (* hcloud.PrimaryIP , error ) {
1154
+ raw := d .PrimaryIPv4
1155
+ if raw == "" {
1156
+ return nil , nil
1157
+ } else if d .cachedPrimaryIPv4 != nil {
1158
+ return d .cachedPrimaryIPv4 , nil
1159
+ }
1160
+
1161
+ ip , err := d .resolvePrimaryIP (raw )
1162
+ d .cachedPrimaryIPv4 = ip
1163
+ return ip , err
1164
+ }
1165
+
1166
+ func (d * Driver ) getPrimaryIPv6 () (* hcloud.PrimaryIP , error ) {
1167
+ raw := d .PrimaryIPv6
1168
+ if raw == "" {
1169
+ return nil , nil
1170
+ } else if d .cachedPrimaryIPv6 != nil {
1171
+ return d .cachedPrimaryIPv6 , nil
1172
+ }
1173
+
1174
+ ip , err := d .resolvePrimaryIP (raw )
1175
+ d .cachedPrimaryIPv6 = ip
1176
+ return ip , err
1177
+ }
1178
+
1179
+ func (d * Driver ) resolvePrimaryIP (raw string ) (* hcloud.PrimaryIP , error ) {
1180
+ client := d .getClient ().PrimaryIP
1181
+
1182
+ var getter func (context.Context , string ) (* hcloud.PrimaryIP , * hcloud.Response , error )
1183
+ if net .ParseIP (raw ) != nil {
1184
+ getter = client .GetByIP
1185
+ } else {
1186
+ getter = client .Get
1187
+ }
1188
+
1189
+ ip , _ , err := getter (context .Background (), raw )
1190
+
1191
+ if err != nil {
1192
+ return nil , fmt .Errorf ("could not get primary IP: %w" , err )
1193
+ }
1194
+
1195
+ if ip != nil {
1196
+ return ip , nil
1197
+ }
1198
+
1199
+ return nil , fmt .Errorf ("primary IP not found: %v" , raw )
1200
+ }
0 commit comments