github.com/openshift/installer@v1.4.17/pkg/asset/installconfig/ssh.go (about)

     1  package installconfig
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"sort"
     9  
    10  	survey "github.com/AlecAivazis/survey/v2"
    11  	"github.com/AlecAivazis/survey/v2/core"
    12  	"github.com/pkg/errors"
    13  
    14  	"github.com/openshift/installer/pkg/asset"
    15  	"github.com/openshift/installer/pkg/validate"
    16  )
    17  
    18  const (
    19  	noSSHKey = "<none>"
    20  )
    21  
    22  type sshPublicKey struct {
    23  	Key string
    24  }
    25  
    26  var _ asset.Asset = (*sshPublicKey)(nil)
    27  
    28  // Dependencies returns no dependencies.
    29  func (a *sshPublicKey) Dependencies() []asset.Asset {
    30  	return nil
    31  }
    32  
    33  func readSSHKey(path string) (string, error) {
    34  	keyAsBytes, err := os.ReadFile(path)
    35  	if err != nil {
    36  		return "", err
    37  	}
    38  
    39  	key := string(keyAsBytes)
    40  
    41  	err = validate.SSHPublicKey(key)
    42  	if err != nil {
    43  		return "", err
    44  	}
    45  
    46  	return key, nil
    47  }
    48  
    49  // Generate generates the SSH public key asset.
    50  func (a *sshPublicKey) Generate(context.Context, asset.Parents) error {
    51  	pubKeys := map[string]string{
    52  		noSSHKey: "",
    53  	}
    54  	home := os.Getenv("HOME")
    55  	if home != "" {
    56  		paths, err := filepath.Glob(filepath.Join(home, ".ssh", "*.pub"))
    57  		if err != nil {
    58  			return errors.Wrap(err, "failed to glob for public key files")
    59  		}
    60  		for _, path := range paths {
    61  			key, err := readSSHKey(path)
    62  			if err != nil {
    63  				continue
    64  			}
    65  			pubKeys[path] = key
    66  		}
    67  	}
    68  
    69  	if len(pubKeys) == 1 {
    70  		for _, value := range pubKeys {
    71  			a.Key = value
    72  		}
    73  		return nil
    74  	}
    75  
    76  	var paths []string
    77  	for path := range pubKeys {
    78  		paths = append(paths, path)
    79  	}
    80  	sort.Strings(paths)
    81  
    82  	var path string
    83  	if err := survey.AskOne(
    84  		&survey.Select{
    85  			Message: "SSH Public Key",
    86  			Help:    "The SSH public key used to access all nodes within the cluster. This is optional.",
    87  			Options: paths,
    88  			Default: noSSHKey,
    89  		},
    90  		&path,
    91  		survey.WithValidator(func(ans interface{}) error {
    92  			choice := ans.(core.OptionAnswer).Value
    93  			i := sort.SearchStrings(paths, choice)
    94  			if i == len(paths) || paths[i] != choice {
    95  				return fmt.Errorf("invalid path %q", choice)
    96  			}
    97  			return nil
    98  		}),
    99  	); err != nil {
   100  		return errors.Wrap(err, "failed UserInput")
   101  	}
   102  
   103  	a.Key = pubKeys[path]
   104  	return nil
   105  }
   106  
   107  // Name returns the human-friendly name of the asset.
   108  func (a sshPublicKey) Name() string {
   109  	return "SSH Key"
   110  }