@@ -34,13 +34,17 @@ type Driver struct {
34
34
cachedKey * hcloud.SSHKey
35
35
IsExistingKey bool
36
36
originalKey string
37
- danglingKey bool
37
+ danglingKeys [] * hcloud. SSHKey
38
38
ServerID int
39
39
userData string
40
40
volumes []string
41
41
networks []string
42
42
UsePrivateNetwork bool
43
43
cachedServer * hcloud.Server
44
+
45
+ additionalKeys []string
46
+ AdditionalKeyIDs []int
47
+ cachedAdditionalKeys []* hcloud.SSHKey
44
48
}
45
49
46
50
const (
@@ -58,14 +62,15 @@ const (
58
62
flagVolumes = "hetzner-volumes"
59
63
flagNetworks = "hetzner-networks"
60
64
flagUsePrivateNetwork = "hetzner-use-private-network"
65
+ flagAdditionalKeys = "hetzner-additional-key"
61
66
)
62
67
63
68
func NewDriver () * Driver {
64
69
return & Driver {
65
70
Image : defaultImage ,
66
71
Type : defaultType ,
67
72
IsExistingKey : false ,
68
- danglingKey : false ,
73
+ danglingKeys : [] * hcloud. SSHKey {} ,
69
74
BaseDriver : & drivers.BaseDriver {
70
75
SSHUser : drivers .DefaultSSHUser ,
71
76
SSHPort : drivers .DefaultSSHPort ,
@@ -143,6 +148,12 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
143
148
Name : flagUsePrivateNetwork ,
144
149
Usage : "Use private network" ,
145
150
},
151
+ mcnflag.StringSliceFlag {
152
+ EnvVar : "HETZNER_ADDITIONAL_KEYS" ,
153
+ Name : flagAdditionalKeys ,
154
+ Usage : "Additional public keys to be attached to the server" ,
155
+ Value : []string {},
156
+ },
146
157
}
147
158
}
148
159
@@ -159,6 +170,7 @@ func (d *Driver) SetConfigFromFlags(opts drivers.DriverOptions) error {
159
170
d .volumes = opts .StringSlice (flagVolumes )
160
171
d .networks = opts .StringSlice (flagNetworks )
161
172
d .UsePrivateNetwork = opts .Bool (flagUsePrivateNetwork )
173
+ d .additionalKeys = opts .StringSlice (flagAdditionalKeys )
162
174
163
175
d .SetSwarmConfigFromFlags (opts )
164
176
@@ -233,6 +245,7 @@ func (d *Driver) Create() error {
233
245
}
234
246
}
235
247
248
+ defer d .destroyDanglingKeys ()
236
249
if d .KeyID == 0 {
237
250
log .Infof ("Creating SSH key..." )
238
251
@@ -242,30 +255,44 @@ func (d *Driver) Create() error {
242
255
}
243
256
244
257
key , err := d .getRemoteKeyWithSameFingerprint (buf )
258
+ if err != nil {
259
+ return errors .Wrap (err , "error retrieving potentially existing key" )
260
+ }
245
261
if key == nil {
246
262
log .Infof ("SSH key not found in Hetzner. Uploading..." )
247
263
248
- keyopts := hcloud.SSHKeyCreateOpts {
249
- Name : d .GetMachineName (),
250
- PublicKey : string (buf ),
251
- }
252
-
253
- key , _ , err = d .getClient ().SSHKey .Create (context .Background (), keyopts )
264
+ key , err = d .makeKey (d .GetMachineName (), string (buf ))
254
265
if err != nil {
255
- return errors .Wrap (err , "could not create ssh key" )
256
- } else if key == nil {
257
- return errors .Errorf ("key upload did not return an error, but key was nil" )
266
+ return err
258
267
}
259
-
260
- d .danglingKey = true
261
- defer d .destroyDanglingKey ()
262
268
} else {
263
269
d .IsExistingKey = true
264
270
log .Debugf ("SSH key found in Hetzner. ID: %d" , key .ID )
265
271
}
266
272
267
273
d .KeyID = key .ID
268
274
}
275
+ for i , pubkey := range d .additionalKeys {
276
+ key , err := d .getRemoteKeyWithSameFingerprint ([]byte (pubkey ))
277
+ if err != nil {
278
+ return errors .Wrapf (err , "error checking for existing key for %v" , pubkey )
279
+ }
280
+ if key == nil {
281
+ log .Infof ("Creating new key for %v..." , pubkey )
282
+ key , err = d .makeKey (fmt .Sprintf ("%v-additional-%d" , d .GetMachineName (), i ), pubkey )
283
+
284
+ if err != nil {
285
+ return errors .Wrapf (err , "error creating new key for %v" , pubkey )
286
+ }
287
+
288
+ log .Infof (" -> Created %v" , key .ID )
289
+ d .AdditionalKeyIDs = append (d .AdditionalKeyIDs , key .ID )
290
+ } else {
291
+ log .Infof ("Using existing key (%v) %v" , key .ID , key .Name )
292
+ }
293
+
294
+ d .cachedAdditionalKeys = append (d .cachedAdditionalKeys , key )
295
+ }
269
296
270
297
log .Infof ("Creating Hetzner server..." )
271
298
@@ -313,7 +340,7 @@ func (d *Driver) Create() error {
313
340
if err != nil {
314
341
return errors .Wrap (err , "could not get ssh key" )
315
342
}
316
- srvopts .SSHKeys = append (srvopts . SSHKeys , key )
343
+ srvopts .SSHKeys = append (d . cachedAdditionalKeys , key )
317
344
318
345
srv , _ , err := d .getClient ().Server .Create (context .Background (), srvopts )
319
346
if err != nil {
@@ -361,24 +388,40 @@ func (d *Driver) Create() error {
361
388
}
362
389
363
390
log .Infof (" -> Server %s[%d] ready. Ip %s" , srv .Server .Name , srv .Server .ID , d .IPAddress )
364
- d .danglingKey = false
391
+ // Successful creation, so no keys dangle anymore
392
+ d .danglingKeys = nil
365
393
366
394
return nil
367
395
}
368
396
369
- func (d * Driver ) destroyDanglingKey () {
370
- if d .danglingKey && ! d .IsExistingKey && d .KeyID != 0 {
371
- key , err := d .getKey ()
372
- if err != nil {
373
- log .Errorf ("could not get key: %v" , err )
374
- return
375
- }
397
+ // Creates a new key for the machine and appends it to the dangling key list
398
+ func (d * Driver ) makeKey (name string , pubkey string ) (* hcloud.SSHKey , error ) {
399
+ keyopts := hcloud.SSHKeyCreateOpts {
400
+ Name : name ,
401
+ PublicKey : pubkey ,
402
+ }
403
+
404
+ key , _ , err := d .getClient ().SSHKey .Create (context .Background (), keyopts )
405
+ if err != nil {
406
+ return nil , errors .Wrap (err , "could not create ssh key" )
407
+ } else if key == nil {
408
+ return nil , errors .Errorf ("key upload did not return an error, but key was nil" )
409
+ }
410
+
411
+ d .danglingKeys = append (d .danglingKeys , key )
412
+ return key , nil
413
+ }
414
+
415
+ func (d * Driver ) destroyDanglingKeys () {
416
+ if ! d .IsExistingKey {
417
+ d .KeyID = 0
418
+ }
376
419
420
+ for _ , key := range d .danglingKeys {
377
421
if _ , err := d .getClient ().SSHKey .Delete (context .Background (), key ); err != nil {
378
422
log .Errorf ("could not delete ssh key: %v" , err )
379
423
return
380
424
}
381
- d .KeyID = 0
382
425
}
383
426
}
384
427
@@ -437,6 +480,22 @@ func (d *Driver) Remove() error {
437
480
}
438
481
}
439
482
483
+ // Failing to remove these is just a soft error
484
+ for i , id := range d .AdditionalKeyIDs {
485
+ log .Infof (" -> Destroying additional key #%d (%d)" , i , id )
486
+ key , _ , err := d .getClient ().SSHKey .GetByID (context .Background (), id )
487
+ if err != nil {
488
+ log .Warnf (" -> -> could not retrieve key %v" , err )
489
+ } else if key == nil {
490
+ log .Warnf (" -> -> %d no longer exists" , id )
491
+ }
492
+
493
+ _ , err = d .getClient ().SSHKey .Delete (context .Background (), key )
494
+ if err != nil {
495
+ log .Warnf (" -> -> could not remove key: %v" , err )
496
+ }
497
+ }
498
+
440
499
if ! d .IsExistingKey && d .KeyID != 0 {
441
500
key , err := d .getKey ()
442
501
if err != nil {
0 commit comments