github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/raft/rafttransport/manifold.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package rafttransport 5 6 import ( 7 "time" 8 9 "github.com/hashicorp/raft" 10 "github.com/juju/clock" 11 "github.com/juju/errors" 12 "github.com/juju/pubsub" 13 "gopkg.in/juju/worker.v1" 14 "gopkg.in/juju/worker.v1/dependency" 15 16 "github.com/juju/juju/agent" 17 "github.com/juju/juju/api" 18 "github.com/juju/juju/apiserver/apiserverhttp" 19 "github.com/juju/juju/apiserver/httpcontext" 20 ) 21 22 // raftNetworkTimeout is how long the transport should wait before 23 // failing a network interaction. 24 const raftNetworkTimeout = 30 * time.Second 25 26 // ManifoldConfig holds the information necessary to run an apiserver-based 27 // raft transport worker in a dependency.Engine. 28 type ManifoldConfig struct { 29 ClockName string 30 AgentName string 31 AuthenticatorName string 32 HubName string 33 MuxName string 34 35 DialConn DialConnFunc 36 NewWorker func(Config) (worker.Worker, error) 37 38 // Path is the path of the raft HTTP endpoint. 39 Path string 40 } 41 42 // Validate validates the manifold configuration. 43 func (config ManifoldConfig) Validate() error { 44 if config.AgentName == "" { 45 return errors.NotValidf("empty AgentName") 46 } 47 if config.AuthenticatorName == "" { 48 return errors.NotValidf("empty AuthenticatorName") 49 } 50 if config.HubName == "" { 51 return errors.NotValidf("empty HubName") 52 } 53 if config.MuxName == "" { 54 return errors.NotValidf("empty MuxName") 55 } 56 if config.DialConn == nil { 57 return errors.NotValidf("nil DialConn") 58 } 59 if config.NewWorker == nil { 60 return errors.NotValidf("nil NewWorker") 61 } 62 if config.Path == "" { 63 return errors.NotValidf("empty Path") 64 } 65 return nil 66 } 67 68 // Manifold returns a dependency.Manifold that will run an apiserver-based 69 // raft transport worker. 70 func Manifold(config ManifoldConfig) dependency.Manifold { 71 return dependency.Manifold{ 72 Inputs: []string{ 73 config.ClockName, 74 config.AgentName, 75 config.AuthenticatorName, 76 config.HubName, 77 config.MuxName, 78 }, 79 Start: config.start, 80 Output: transportOutput, 81 } 82 } 83 84 // start is a method on ManifoldConfig because it's more readable than a closure. 85 func (config ManifoldConfig) start(context dependency.Context) (worker.Worker, error) { 86 if err := config.Validate(); err != nil { 87 return nil, errors.Trace(err) 88 } 89 90 var clk clock.Clock 91 if err := context.Get(config.ClockName, &clk); err != nil { 92 return nil, errors.Trace(err) 93 } 94 95 var agent agent.Agent 96 if err := context.Get(config.AgentName, &agent); err != nil { 97 return nil, errors.Trace(err) 98 } 99 100 var authenticator httpcontext.Authenticator 101 if err := context.Get(config.AuthenticatorName, &authenticator); err != nil { 102 return nil, errors.Trace(err) 103 } 104 105 var hub *pubsub.StructuredHub 106 if err := context.Get(config.HubName, &hub); err != nil { 107 return nil, errors.Trace(err) 108 } 109 110 var mux *apiserverhttp.Mux 111 if err := context.Get(config.MuxName, &mux); err != nil { 112 return nil, errors.Trace(err) 113 } 114 115 apiInfo, ok := agent.CurrentConfig().APIInfo() 116 if !ok { 117 return nil, dependency.ErrMissing 118 } 119 certPool, err := api.CreateCertPool(apiInfo.CACert) 120 if err != nil { 121 return nil, errors.Trace(err) 122 } 123 124 return config.NewWorker(Config{ 125 APIInfo: apiInfo, 126 Authenticator: authenticator, 127 DialConn: config.DialConn, 128 Hub: hub, 129 Mux: mux, 130 Path: config.Path, 131 LocalID: raft.ServerID(agent.CurrentConfig().Tag().Id()), 132 TLSConfig: api.NewTLSConfig(certPool), 133 Clock: clk, 134 Timeout: raftNetworkTimeout, 135 }) 136 } 137 138 func transportOutput(in worker.Worker, out interface{}) error { 139 t, ok := in.(raft.Transport) 140 if !ok { 141 return errors.Errorf("expected input of type %T, got %T", t, in) 142 } 143 tout, ok := out.(*raft.Transport) 144 if ok { 145 *tout = t 146 return nil 147 } 148 return errors.Errorf("expected output of type %T, got %T", tout, out) 149 }