Skip to content

Commit 305bb9a

Browse files
Break up server creation logic
1 parent 7ac9eec commit 305bb9a

File tree

1 file changed

+175
-112
lines changed

1 file changed

+175
-112
lines changed

driver.go

Lines changed: 175 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -276,179 +276,242 @@ func (d *Driver) PreCreateCheck() error {
276276

277277
// Create actually creates the hetzner-cloud server; see [drivers.Driver.Create]
278278
func (d *Driver) Create() error {
279-
if d.originalKey != "" {
280-
log.Debugf("Copying SSH key...")
281-
if err := d.copySSHKeyPair(d.originalKey); err != nil {
282-
return errors.Wrap(err, "could not copy ssh key pair")
283-
}
284-
} else {
285-
log.Debugf("Generating SSH key...")
286-
if err := mcnssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
287-
return errors.Wrap(err, "could not generate ssh key")
288-
}
279+
err := d.prepareLocalKey()
280+
if err != nil {
281+
return err
289282
}
290283

291284
defer d.destroyDanglingKeys()
292-
if d.KeyID == 0 {
293-
log.Infof("Creating SSH key...")
285+
err = d.createRemoteKeys()
286+
if err != nil {
287+
return err
288+
}
294289

295-
buf, err := ioutil.ReadFile(d.GetSSHKeyPath() + ".pub")
296-
if err != nil {
297-
return errors.Wrap(err, "could not read ssh public key")
298-
}
290+
log.Infof("Creating Hetzner server...")
299291

300-
key, err := d.getRemoteKeyWithSameFingerprint(buf)
301-
if err != nil {
302-
return errors.Wrap(err, "error retrieving potentially existing key")
303-
}
304-
if key == nil {
305-
log.Infof("SSH key not found in Hetzner. Uploading...")
292+
srvopts, err := d.makeCreateServerOptions()
293+
if err != nil {
294+
return err
295+
}
306296

307-
key, err = d.makeKey(d.GetMachineName(), string(buf))
297+
srv, _, err := d.getClient().Server.Create(context.Background(), *srvopts)
298+
if err != nil {
299+
return errors.Wrap(err, "could not create server")
300+
}
301+
302+
log.Infof(" -> Creating server %s[%d] in %s[%d]", srv.Server.Name, srv.Server.ID, srv.Action.Command, srv.Action.ID)
303+
if err = d.waitForAction(srv.Action); err != nil {
304+
return errors.Wrap(err, "could not wait for action")
305+
}
306+
307+
d.ServerID = srv.Server.ID
308+
log.Infof(" -> Server %s[%d]: Waiting to come up...", srv.Server.Name, srv.Server.ID)
309+
310+
err = d.waitForRunningServer()
311+
if err != nil {
312+
return err
313+
}
314+
315+
err = d.configureNetworkAccess(srv)
316+
if err != nil {
317+
return err
318+
}
319+
320+
log.Infof(" -> Server %s[%d] ready. Ip %s", srv.Server.Name, srv.Server.ID, d.IPAddress)
321+
// Successful creation, so no keys dangle anymore
322+
d.danglingKeys = nil
323+
324+
return nil
325+
}
326+
327+
func (d *Driver) configureNetworkAccess(srv hcloud.ServerCreateResult) error {
328+
if d.UsePrivateNetwork {
329+
for {
330+
// we need to wait until network is attached
331+
log.Infof("Wait until private network attached ...")
332+
server, _, err := d.getClient().Server.GetByID(context.Background(), srv.Server.ID)
308333
if err != nil {
309-
return err
334+
return errors.Wrapf(err, "could not get newly created server [%d]", srv.Server.ID)
310335
}
311-
} else {
312-
d.IsExistingKey = true
313-
log.Debugf("SSH key found in Hetzner. ID: %d", key.ID)
336+
if server.PrivateNet != nil {
337+
d.IPAddress = server.PrivateNet[0].IP.String()
338+
break
339+
}
340+
time.Sleep(1 * time.Second)
314341
}
315-
316-
d.KeyID = key.ID
342+
} else {
343+
log.Infof("Using public network ...")
344+
d.IPAddress = srv.Server.PublicNet.IPv4.IP.String()
317345
}
318-
for i, pubkey := range d.additionalKeys {
319-
key, err := d.getRemoteKeyWithSameFingerprint([]byte(pubkey))
346+
return nil
347+
}
348+
349+
func (d *Driver) waitForRunningServer() error {
350+
for {
351+
srvstate, err := d.GetState()
320352
if err != nil {
321-
return errors.Wrapf(err, "error checking for existing key for %v", pubkey)
353+
return errors.Wrap(err, "could not get state")
322354
}
323-
if key == nil {
324-
log.Infof("Creating new key for %v...", pubkey)
325-
key, err = d.makeKey(fmt.Sprintf("%v-additional-%d", d.GetMachineName(), i), pubkey)
326-
327-
if err != nil {
328-
return errors.Wrapf(err, "error creating new key for %v", pubkey)
329-
}
330355

331-
log.Infof(" -> Created %v", key.ID)
332-
d.AdditionalKeyIDs = append(d.AdditionalKeyIDs, key.ID)
333-
} else {
334-
log.Infof("Using existing key (%v) %v", key.ID, key.Name)
356+
if srvstate == state.Running {
357+
break
335358
}
336359

337-
d.cachedAdditionalKeys = append(d.cachedAdditionalKeys, key)
360+
time.Sleep(1 * time.Second)
338361
}
362+
return nil
363+
}
339364

340-
log.Infof("Creating Hetzner server...")
341-
365+
func (d *Driver) makeCreateServerOptions() (*hcloud.ServerCreateOpts, error) {
342366
srvopts := hcloud.ServerCreateOpts{
343367
Name: d.GetMachineName(),
344368
UserData: d.userData,
345369
Labels: d.serverLabels,
346370
}
347371

372+
networks, err := d.createNetworks()
373+
if err != nil {
374+
return nil, err
375+
}
376+
srvopts.Networks = networks
377+
378+
firewalls, err := d.createFirewalls()
379+
if err != nil {
380+
return nil, err
381+
}
382+
srvopts.Firewalls = firewalls
383+
384+
volumes, err := d.createVolumes()
385+
if err != nil {
386+
return nil, err
387+
}
388+
srvopts.Volumes = volumes
389+
390+
if srvopts.Location, err = d.getLocation(); err != nil {
391+
return nil, errors.Wrap(err, "could not get location")
392+
}
393+
if srvopts.ServerType, err = d.getType(); err != nil {
394+
return nil, errors.Wrap(err, "could not get type")
395+
}
396+
if srvopts.Image, err = d.getImage(); err != nil {
397+
return nil, errors.Wrap(err, "could not get image")
398+
}
399+
key, err := d.getKey()
400+
if err != nil {
401+
return nil, errors.Wrap(err, "could not get ssh key")
402+
}
403+
srvopts.SSHKeys = append(d.cachedAdditionalKeys, key)
404+
return &srvopts, nil
405+
}
406+
407+
func (d *Driver) createNetworks() ([]*hcloud.Network, error) {
348408
networks := []*hcloud.Network{}
349409
for _, networkIDorName := range d.networks {
350410
network, _, err := d.getClient().Network.Get(context.Background(), networkIDorName)
351411
if err != nil {
352-
return errors.Wrap(err, "could not get network by ID or name")
412+
return nil, errors.Wrap(err, "could not get network by ID or name")
353413
}
354414
if network == nil {
355-
return errors.Errorf("network '%s' not found", networkIDorName)
415+
return nil, errors.Errorf("network '%s' not found", networkIDorName)
356416
}
357417
networks = append(networks, network)
358418
}
359-
srvopts.Networks = networks
419+
return networks, nil
420+
}
360421

422+
func (d *Driver) createFirewalls() ([]*hcloud.ServerCreateFirewall, error) {
361423
firewalls := []*hcloud.ServerCreateFirewall{}
362424
for _, firewallIDorName := range d.firewalls {
363425
firewall, _, err := d.getClient().Firewall.Get(context.Background(), firewallIDorName)
364426
if err != nil {
365-
return errors.Wrap(err, "could not get firewall by ID or name")
427+
return nil, errors.Wrap(err, "could not get firewall by ID or name")
366428
}
367429
if firewall == nil {
368-
return errors.Errorf("firewall '%s' not found", firewallIDorName)
430+
return nil, errors.Errorf("firewall '%s' not found", firewallIDorName)
369431
}
370432
firewalls = append(firewalls, &hcloud.ServerCreateFirewall{Firewall: *firewall})
371433
}
372-
srvopts.Firewalls = firewalls
434+
return firewalls, nil
435+
}
373436

437+
func (d *Driver) createVolumes() ([]*hcloud.Volume, error) {
374438
volumes := []*hcloud.Volume{}
375439
for _, volumeIDorName := range d.volumes {
376440
volume, _, err := d.getClient().Volume.Get(context.Background(), volumeIDorName)
377441
if err != nil {
378-
return errors.Wrap(err, "could not get volume by ID or name")
442+
return nil, errors.Wrap(err, "could not get volume by ID or name")
379443
}
380444
if volume == nil {
381-
return errors.Errorf("volume '%s' not found", volumeIDorName)
445+
return nil, errors.Errorf("volume '%s' not found", volumeIDorName)
382446
}
383447
volumes = append(volumes, volume)
384448
}
385-
srvopts.Volumes = volumes
386-
387-
var err error
388-
if srvopts.Location, err = d.getLocation(); err != nil {
389-
return errors.Wrap(err, "could not get location")
390-
}
391-
if srvopts.ServerType, err = d.getType(); err != nil {
392-
return errors.Wrap(err, "could not get type")
393-
}
394-
if srvopts.Image, err = d.getImage(); err != nil {
395-
return errors.Wrap(err, "could not get image")
396-
}
397-
key, err := d.getKey()
398-
if err != nil {
399-
return errors.Wrap(err, "could not get ssh key")
400-
}
401-
srvopts.SSHKeys = append(d.cachedAdditionalKeys, key)
402-
403-
srv, _, err := d.getClient().Server.Create(context.Background(), srvopts)
404-
if err != nil {
405-
return errors.Wrap(err, "could not create server")
406-
}
449+
return volumes, nil
450+
}
407451

408-
log.Infof(" -> Creating server %s[%d] in %s[%d]", srv.Server.Name, srv.Server.ID, srv.Action.Command, srv.Action.ID)
409-
if err = d.waitForAction(srv.Action); err != nil {
410-
return errors.Wrap(err, "could not wait for action")
411-
}
452+
func (d *Driver) createRemoteKeys() error {
453+
if d.KeyID == 0 {
454+
log.Infof("Creating SSH key...")
412455

413-
d.ServerID = srv.Server.ID
414-
log.Infof(" -> Server %s[%d]: Waiting to come up...", srv.Server.Name, srv.Server.ID)
456+
buf, err := ioutil.ReadFile(d.GetSSHKeyPath() + ".pub")
457+
if err != nil {
458+
return errors.Wrap(err, "could not read ssh public key")
459+
}
415460

416-
for {
417-
srvstate, err := d.GetState()
461+
key, err := d.getRemoteKeyWithSameFingerprint(buf)
418462
if err != nil {
419-
return errors.Wrap(err, "could not get state")
463+
return errors.Wrap(err, "error retrieving potentially existing key")
420464
}
465+
if key == nil {
466+
log.Infof("SSH key not found in Hetzner. Uploading...")
421467

422-
if srvstate == state.Running {
423-
break
468+
key, err = d.makeKey(d.GetMachineName(), string(buf))
469+
if err != nil {
470+
return err
471+
}
472+
} else {
473+
d.IsExistingKey = true
474+
log.Debugf("SSH key found in Hetzner. ID: %d", key.ID)
424475
}
425476

426-
time.Sleep(1 * time.Second)
477+
d.KeyID = key.ID
427478
}
479+
for i, pubkey := range d.additionalKeys {
480+
key, err := d.getRemoteKeyWithSameFingerprint([]byte(pubkey))
481+
if err != nil {
482+
return errors.Wrapf(err, "error checking for existing key for %v", pubkey)
483+
}
484+
if key == nil {
485+
log.Infof("Creating new key for %v...", pubkey)
486+
key, err = d.makeKey(fmt.Sprintf("%v-additional-%d", d.GetMachineName(), i), pubkey)
428487

429-
if d.UsePrivateNetwork {
430-
for {
431-
// we need to wait until network is attached
432-
log.Infof("Wait until private network attached ...")
433-
server, _, err := d.getClient().Server.GetByID(context.Background(), srv.Server.ID)
434488
if err != nil {
435-
return errors.Wrapf(err, "could not get newly created server [%d]", srv.Server.ID)
436-
}
437-
if server.PrivateNet != nil {
438-
d.IPAddress = server.PrivateNet[0].IP.String()
439-
break
489+
return errors.Wrapf(err, "error creating new key for %v", pubkey)
440490
}
441-
time.Sleep(1 * time.Second)
491+
492+
log.Infof(" -> Created %v", key.ID)
493+
d.AdditionalKeyIDs = append(d.AdditionalKeyIDs, key.ID)
494+
} else {
495+
log.Infof("Using existing key (%v) %v", key.ID, key.Name)
442496
}
443-
} else {
444-
log.Infof("Using public network ...")
445-
d.IPAddress = srv.Server.PublicNet.IPv4.IP.String()
446-
}
447497

448-
log.Infof(" -> Server %s[%d] ready. Ip %s", srv.Server.Name, srv.Server.ID, d.IPAddress)
449-
// Successful creation, so no keys dangle anymore
450-
d.danglingKeys = nil
498+
d.cachedAdditionalKeys = append(d.cachedAdditionalKeys, key)
499+
}
500+
return nil
501+
}
451502

503+
func (d *Driver) prepareLocalKey() error {
504+
if d.originalKey != "" {
505+
log.Debugf("Copying SSH key...")
506+
if err := d.copySSHKeyPair(d.originalKey); err != nil {
507+
return errors.Wrap(err, "could not copy ssh key pair")
508+
}
509+
} else {
510+
log.Debugf("Generating SSH key...")
511+
if err := mcnssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
512+
return errors.Wrap(err, "could not generate ssh key")
513+
}
514+
}
452515
return nil
453516
}
454517

@@ -737,19 +800,19 @@ func (d *Driver) getKey() (*hcloud.SSHKey, error) {
737800
return stype, nil
738801
}
739802

740-
func (d *Driver) getRemoteKeyWithSameFingerprint(pubkey_byte []byte) (*hcloud.SSHKey, error) {
741-
pubkey, _, _, _, err := ssh.ParseAuthorizedKey(pubkey_byte)
803+
func (d *Driver) getRemoteKeyWithSameFingerprint(publicKeyBytes []byte) (*hcloud.SSHKey, error) {
804+
publicKey, _, _, _, err := ssh.ParseAuthorizedKey(publicKeyBytes)
742805
if err != nil {
743806
return nil, errors.Wrap(err, "could not parse ssh public key")
744807
}
745808

746-
fp := ssh.FingerprintLegacyMD5(pubkey)
809+
fp := ssh.FingerprintLegacyMD5(publicKey)
747810

748-
remotekey, _, err := d.getClient().SSHKey.GetByFingerprint(context.Background(), fp)
811+
remoteKey, _, err := d.getClient().SSHKey.GetByFingerprint(context.Background(), fp)
749812
if err != nil {
750-
return remotekey, errors.Wrap(err, "could not get sshkey by fingerprint")
813+
return remoteKey, errors.Wrap(err, "could not get sshkey by fingerprint")
751814
}
752-
return remotekey, nil
815+
return remoteKey, nil
753816
}
754817

755818
func (d *Driver) getServerHandle() (*hcloud.Server, error) {

0 commit comments

Comments
 (0)