github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/hostkeyreporter/worker.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package hostkeyreporter 5 6 import ( 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 11 "github.com/juju/errors" 12 "github.com/juju/loggo" 13 "gopkg.in/juju/worker.v1" 14 "gopkg.in/juju/worker.v1/dependency" 15 "gopkg.in/tomb.v2" 16 ) 17 18 var logger = loggo.GetLogger("juju.worker.hostkeyreporter") 19 20 // Facade exposes controller functionality to a Worker. 21 type Facade interface { 22 ReportKeys(machineId string, publicKeys []string) error 23 } 24 25 // Config defines the parameters of the hostkeyreporter worker. 26 type Config struct { 27 Facade Facade 28 MachineId string 29 RootDir string 30 } 31 32 // Validate returns an error if Config cannot drive a hostkeyreporter. 33 func (config Config) Validate() error { 34 if config.Facade == nil { 35 return errors.NotValidf("nil Facade") 36 } 37 if config.MachineId == "" { 38 return errors.NotValidf("empty MachineId") 39 } 40 return nil 41 } 42 43 // New returns a Worker backed by config, or an error. 44 func New(config Config) (worker.Worker, error) { 45 if err := config.Validate(); err != nil { 46 return nil, errors.Trace(err) 47 } 48 w := &hostkeyreporter{config: config} 49 w.tomb.Go(w.run) 50 return w, nil 51 } 52 53 // Worker waits for a model migration to be active, then locks down the 54 // configured fortress and implements the migration. 55 type hostkeyreporter struct { 56 tomb tomb.Tomb 57 config Config 58 } 59 60 // Kill implements worker.Worker. 61 func (w *hostkeyreporter) Kill() { 62 w.tomb.Kill(nil) 63 } 64 65 // Wait implements worker.Worker. 66 func (w *hostkeyreporter) Wait() error { 67 return w.tomb.Wait() 68 } 69 70 func (w *hostkeyreporter) run() error { 71 keys, err := w.readSSHKeys() 72 if err != nil { 73 return errors.Trace(err) 74 } 75 if len(keys) < 1 { 76 return errors.New("no SSH host keys found") 77 } 78 err = w.config.Facade.ReportKeys(w.config.MachineId, keys) 79 if err != nil { 80 return errors.Trace(err) 81 } 82 logger.Debugf("%d SSH host keys reported for machine %s", len(keys), w.config.MachineId) 83 return dependency.ErrUninstall 84 } 85 86 func (w *hostkeyreporter) readSSHKeys() ([]string, error) { 87 sshDir := w.sshDir() 88 _, err := os.Stat(sshDir) 89 if os.IsNotExist(err) { 90 logger.Errorf("%s doesn't exist - giving up", sshDir) 91 return nil, dependency.ErrUninstall 92 } 93 if err != nil { 94 return nil, errors.Trace(err) 95 } 96 97 filenames, err := filepath.Glob(sshDir + "/ssh_host_*_key.pub") 98 if err != nil { 99 return nil, errors.Trace(err) 100 } 101 keys := make([]string, 0, len(filenames)) 102 for _, filename := range filenames { 103 key, err := ioutil.ReadFile(filename) 104 if err != nil { 105 logger.Debugf("unable to read SSH host key (skipping): %v", err) 106 continue 107 } 108 keys = append(keys, string(key)) 109 } 110 return keys, nil 111 } 112 113 func (w *hostkeyreporter) sshDir() string { 114 return filepath.Join(w.config.RootDir, "etc", "ssh") 115 }