Skip to content

Commit c794988

Browse files
Allow additional ssh keys
fixes #53
1 parent 16ecd2b commit c794988

File tree

1 file changed

+83
-24
lines changed

1 file changed

+83
-24
lines changed

driver.go

Lines changed: 83 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,17 @@ type Driver struct {
3434
cachedKey *hcloud.SSHKey
3535
IsExistingKey bool
3636
originalKey string
37-
danglingKey bool
37+
danglingKeys []*hcloud.SSHKey
3838
ServerID int
3939
userData string
4040
volumes []string
4141
networks []string
4242
UsePrivateNetwork bool
4343
cachedServer *hcloud.Server
44+
45+
additionalKeys []string
46+
AdditionalKeyIDs []int
47+
cachedAdditionalKeys []*hcloud.SSHKey
4448
}
4549

4650
const (
@@ -58,14 +62,15 @@ const (
5862
flagVolumes = "hetzner-volumes"
5963
flagNetworks = "hetzner-networks"
6064
flagUsePrivateNetwork = "hetzner-use-private-network"
65+
flagAdditionalKeys = "hetzner-additional-key"
6166
)
6267

6368
func NewDriver() *Driver {
6469
return &Driver{
6570
Image: defaultImage,
6671
Type: defaultType,
6772
IsExistingKey: false,
68-
danglingKey: false,
73+
danglingKeys: []*hcloud.SSHKey{},
6974
BaseDriver: &drivers.BaseDriver{
7075
SSHUser: drivers.DefaultSSHUser,
7176
SSHPort: drivers.DefaultSSHPort,
@@ -143,6 +148,12 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
143148
Name: flagUsePrivateNetwork,
144149
Usage: "Use private network",
145150
},
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+
},
146157
}
147158
}
148159

@@ -159,6 +170,7 @@ func (d *Driver) SetConfigFromFlags(opts drivers.DriverOptions) error {
159170
d.volumes = opts.StringSlice(flagVolumes)
160171
d.networks = opts.StringSlice(flagNetworks)
161172
d.UsePrivateNetwork = opts.Bool(flagUsePrivateNetwork)
173+
d.additionalKeys = opts.StringSlice(flagAdditionalKeys)
162174

163175
d.SetSwarmConfigFromFlags(opts)
164176

@@ -233,6 +245,7 @@ func (d *Driver) Create() error {
233245
}
234246
}
235247

248+
defer d.destroyDanglingKeys()
236249
if d.KeyID == 0 {
237250
log.Infof("Creating SSH key...")
238251

@@ -242,30 +255,44 @@ func (d *Driver) Create() error {
242255
}
243256

244257
key, err := d.getRemoteKeyWithSameFingerprint(buf)
258+
if err != nil {
259+
return errors.Wrap(err, "error retrieving potentially existing key")
260+
}
245261
if key == nil {
246262
log.Infof("SSH key not found in Hetzner. Uploading...")
247263

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))
254265
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
258267
}
259-
260-
d.danglingKey = true
261-
defer d.destroyDanglingKey()
262268
} else {
263269
d.IsExistingKey = true
264270
log.Debugf("SSH key found in Hetzner. ID: %d", key.ID)
265271
}
266272

267273
d.KeyID = key.ID
268274
}
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+
}
269296

270297
log.Infof("Creating Hetzner server...")
271298

@@ -313,7 +340,7 @@ func (d *Driver) Create() error {
313340
if err != nil {
314341
return errors.Wrap(err, "could not get ssh key")
315342
}
316-
srvopts.SSHKeys = append(srvopts.SSHKeys, key)
343+
srvopts.SSHKeys = append(d.cachedAdditionalKeys, key)
317344

318345
srv, _, err := d.getClient().Server.Create(context.Background(), srvopts)
319346
if err != nil {
@@ -361,24 +388,40 @@ func (d *Driver) Create() error {
361388
}
362389

363390
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
365393

366394
return nil
367395
}
368396

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+
}
376419

420+
for _, key := range d.danglingKeys {
377421
if _, err := d.getClient().SSHKey.Delete(context.Background(), key); err != nil {
378422
log.Errorf("could not delete ssh key: %v", err)
379423
return
380424
}
381-
d.KeyID = 0
382425
}
383426
}
384427

@@ -437,6 +480,22 @@ func (d *Driver) Remove() error {
437480
}
438481
}
439482

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+
440499
if !d.IsExistingKey && d.KeyID != 0 {
441500
key, err := d.getKey()
442501
if err != nil {

0 commit comments

Comments
 (0)