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