github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/jujud/agent/agenttest/agent.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package agenttest 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/clock" 11 "github.com/juju/cmd" 12 "github.com/juju/cmd/cmdtesting" 13 "github.com/juju/errors" 14 "github.com/juju/os/series" 15 "github.com/juju/replicaset" 16 gitjujutesting "github.com/juju/testing" 17 jc "github.com/juju/testing/checkers" 18 "github.com/juju/utils/arch" 19 "github.com/juju/version" 20 gc "gopkg.in/check.v1" 21 "gopkg.in/juju/names.v2" 22 "gopkg.in/mgo.v2" 23 24 "github.com/juju/juju/agent" 25 agenttools "github.com/juju/juju/agent/tools" 26 "github.com/juju/juju/apiserver/params" 27 cmdutil "github.com/juju/juju/cmd/jujud/util" 28 "github.com/juju/juju/controller" 29 "github.com/juju/juju/environs/filestorage" 30 envtesting "github.com/juju/juju/environs/testing" 31 envtools "github.com/juju/juju/environs/tools" 32 "github.com/juju/juju/juju/testing" 33 "github.com/juju/juju/mongo" 34 "github.com/juju/juju/mongo/mongotest" 35 "github.com/juju/juju/network" 36 "github.com/juju/juju/state" 37 "github.com/juju/juju/state/stateenvirons" 38 coretesting "github.com/juju/juju/testing" 39 coretools "github.com/juju/juju/tools" 40 jujuversion "github.com/juju/juju/version" 41 "github.com/juju/juju/worker/peergrouper" 42 ) 43 44 type patchingSuite interface { 45 PatchValue(interface{}, interface{}) 46 } 47 48 // InstallFakeEnsureMongo creates a new FakeEnsureMongo, patching 49 // out replicaset.CurrentConfig and cmdutil.EnsureMongoServer. 50 func InstallFakeEnsureMongo(suite patchingSuite) *FakeEnsureMongo { 51 f := &FakeEnsureMongo{ 52 ServiceInstalled: true, 53 } 54 suite.PatchValue(&mongo.IsServiceInstalled, f.IsServiceInstalled) 55 suite.PatchValue(&replicaset.CurrentConfig, f.CurrentConfig) 56 suite.PatchValue(&cmdutil.EnsureMongoServer, f.EnsureMongo) 57 return f 58 } 59 60 // FakeEnsureMongo provides test fakes for the functions used to 61 // initialise MongoDB. 62 type FakeEnsureMongo struct { 63 EnsureCount int 64 InitiateCount int 65 DataDir string 66 OplogSize int 67 Info state.StateServingInfo 68 InitiateParams peergrouper.InitiateMongoParams 69 Err error 70 ServiceInstalled bool 71 } 72 73 func (f *FakeEnsureMongo) IsServiceInstalled() (bool, error) { 74 return f.ServiceInstalled, nil 75 } 76 77 func (f *FakeEnsureMongo) CurrentConfig(*mgo.Session) (*replicaset.Config, error) { 78 // Return a dummy replicaset config that's good enough to 79 // indicate that the replicaset is initiated. 80 return &replicaset.Config{ 81 Members: []replicaset.Member{{}}, 82 }, nil 83 } 84 85 func (f *FakeEnsureMongo) EnsureMongo(args mongo.EnsureServerParams) (mongo.Version, error) { 86 f.EnsureCount++ 87 f.DataDir, f.OplogSize = args.DataDir, args.OplogSize 88 f.Info = state.StateServingInfo{ 89 APIPort: args.APIPort, 90 StatePort: args.StatePort, 91 Cert: args.Cert, 92 PrivateKey: args.PrivateKey, 93 CAPrivateKey: args.CAPrivateKey, 94 SharedSecret: args.SharedSecret, 95 SystemIdentity: args.SystemIdentity, 96 } 97 v, err := gitjujutesting.MongodVersion() 98 if err != nil { 99 return mongo.Version{}, errors.Trace(err) 100 } 101 return mongo.Version{ 102 Major: v.Major, 103 Minor: v.Minor, 104 Patch: fmt.Sprint(v.Patch), 105 }, f.Err 106 } 107 108 func (f *FakeEnsureMongo) InitiateMongo(p peergrouper.InitiateMongoParams) error { 109 f.InitiateCount++ 110 f.InitiateParams = p 111 return nil 112 } 113 114 // agentSuite is a fixture to be used by agent test suites. 115 type AgentSuite struct { 116 oldRestartDelay time.Duration 117 testing.JujuConnSuite 118 } 119 120 // PrimeAgent writes the configuration file and tools for an agent 121 // with the given entity name. It returns the agent's configuration and the 122 // current tools. 123 func (s *AgentSuite) PrimeAgent(c *gc.C, tag names.Tag, password string) (agent.ConfigSetterWriter, *coretools.Tools) { 124 vers := version.Binary{ 125 Number: jujuversion.Current, 126 Arch: arch.HostArch(), 127 Series: series.MustHostSeries(), 128 } 129 return s.PrimeAgentVersion(c, tag, password, vers) 130 } 131 132 // PrimeAgentVersion writes the configuration file and tools with version 133 // vers for an agent with the given entity name. It returns the agent's 134 // configuration and the current tools. 135 func (s *AgentSuite) PrimeAgentVersion(c *gc.C, tag names.Tag, password string, vers version.Binary) (agent.ConfigSetterWriter, *coretools.Tools) { 136 c.Logf("priming agent %s", tag.String()) 137 stor, err := filestorage.NewFileStorageWriter(c.MkDir()) 138 c.Assert(err, jc.ErrorIsNil) 139 agentTools := envtesting.PrimeTools(c, stor, s.DataDir(), "released", vers) 140 err = envtools.MergeAndWriteMetadata(stor, "released", "released", coretools.List{agentTools}, envtools.DoNotWriteMirrors) 141 tools1, err := agenttools.ChangeAgentTools(s.DataDir(), tag.String(), vers) 142 c.Assert(err, jc.ErrorIsNil) 143 c.Assert(tools1, gc.DeepEquals, agentTools) 144 145 stateInfo := s.MongoInfo(c) 146 apiInfo := s.APIInfo(c) 147 paths := agent.DefaultPaths 148 paths.DataDir = s.DataDir() 149 paths.LogDir = s.LogDir 150 paths.MetricsSpoolDir = c.MkDir() 151 conf, err := agent.NewAgentConfig( 152 agent.AgentConfigParams{ 153 Paths: paths, 154 Tag: tag, 155 UpgradedToVersion: vers.Number, 156 Password: password, 157 Nonce: agent.BootstrapNonce, 158 APIAddresses: apiInfo.Addrs, 159 CACert: stateInfo.CACert, 160 Controller: coretesting.ControllerTag, 161 Model: apiInfo.ModelTag, 162 }) 163 c.Assert(err, jc.ErrorIsNil) 164 conf.SetPassword(password) 165 c.Assert(conf.Write(), gc.IsNil) 166 s.primeAPIHostPorts(c) 167 return conf, agentTools 168 } 169 170 // PrimeStateAgent writes the configuration file and tools for 171 // a state agent with the given entity name. It returns the agent's 172 // configuration and the current tools. 173 func (s *AgentSuite) PrimeStateAgent(c *gc.C, tag names.Tag, password string) (agent.ConfigSetterWriter, *coretools.Tools) { 174 vers := version.Binary{ 175 Number: jujuversion.Current, 176 Arch: arch.HostArch(), 177 Series: series.MustHostSeries(), 178 } 179 return s.PrimeStateAgentVersion(c, tag, password, vers) 180 } 181 182 // PrimeStateAgentVersion writes the configuration file and tools with 183 // version vers for a state agent with the given entity name. It 184 // returns the agent's configuration and the current tools. 185 func (s *AgentSuite) PrimeStateAgentVersion(c *gc.C, tag names.Tag, password string, vers version.Binary) ( 186 agent.ConfigSetterWriter, *coretools.Tools, 187 ) { 188 stor, err := filestorage.NewFileStorageWriter(c.MkDir()) 189 c.Assert(err, jc.ErrorIsNil) 190 agentTools := envtesting.PrimeTools(c, stor, s.DataDir(), "released", vers) 191 tools1, err := agenttools.ChangeAgentTools(s.DataDir(), tag.String(), vers) 192 c.Assert(err, jc.ErrorIsNil) 193 c.Assert(tools1, gc.DeepEquals, agentTools) 194 195 model, err := s.State.Model() 196 c.Assert(err, jc.ErrorIsNil) 197 198 conf := s.WriteStateAgentConfig(c, tag, password, vers, model.ModelTag()) 199 s.primeAPIHostPorts(c) 200 return conf, agentTools 201 } 202 203 // WriteStateAgentConfig creates and writes a state agent config. 204 func (s *AgentSuite) WriteStateAgentConfig( 205 c *gc.C, 206 tag names.Tag, 207 password string, 208 vers version.Binary, 209 modelTag names.ModelTag, 210 ) agent.ConfigSetterWriter { 211 stateInfo := s.MongoInfo(c) 212 apiPort := gitjujutesting.FindTCPPort() 213 s.SetControllerConfigAPIPort(c, apiPort) 214 apiAddr := []string{fmt.Sprintf("localhost:%d", apiPort)} 215 conf, err := agent.NewStateMachineConfig( 216 agent.AgentConfigParams{ 217 Paths: agent.NewPathsWithDefaults(agent.Paths{ 218 DataDir: s.DataDir(), 219 LogDir: s.LogDir, 220 }), 221 Tag: tag, 222 UpgradedToVersion: vers.Number, 223 Password: password, 224 Nonce: agent.BootstrapNonce, 225 APIAddresses: apiAddr, 226 CACert: stateInfo.CACert, 227 Controller: s.State.ControllerTag(), 228 Model: modelTag, 229 }, 230 params.StateServingInfo{ 231 Cert: coretesting.ServerCert, 232 PrivateKey: coretesting.ServerKey, 233 CAPrivateKey: coretesting.CAKey, 234 StatePort: gitjujutesting.MgoServer.Port(), 235 APIPort: apiPort, 236 }) 237 c.Assert(err, jc.ErrorIsNil) 238 conf.SetPassword(password) 239 c.Assert(conf.Write(), gc.IsNil) 240 return conf 241 } 242 243 // SetControllerConfigAPIPort resets the API port in controller config 244 // to the value provided - this is useful in tests that create 245 // multiple agents and only start one, so that the API port the http 246 // server listens on matches the one the agent tries to connect to. 247 func (s *AgentSuite) SetControllerConfigAPIPort(c *gc.C, apiPort int) { 248 // Need to update the controller config with this new API port as 249 // well - this is a nasty hack but... oh well! 250 controller.AllowedUpdateConfigAttributes.Add("api-port") 251 defer func() { 252 controller.AllowedUpdateConfigAttributes.Remove("api-port") 253 }() 254 err := s.State.UpdateControllerConfig(map[string]interface{}{ 255 "api-port": apiPort, 256 }, nil) 257 c.Assert(err, jc.ErrorIsNil) 258 // Ensure that the local controller config is also up to date. 259 s.ControllerConfig["api-port"] = apiPort 260 } 261 262 func (s *AgentSuite) primeAPIHostPorts(c *gc.C) { 263 apiInfo := s.APIInfo(c) 264 265 c.Assert(apiInfo.Addrs, gc.HasLen, 1) 266 hostPorts, err := network.ParseHostPorts(apiInfo.Addrs[0]) 267 c.Assert(err, jc.ErrorIsNil) 268 269 err = s.State.SetAPIHostPorts([][]network.HostPort{hostPorts}) 270 c.Assert(err, jc.ErrorIsNil) 271 272 c.Logf("api host ports primed %#v", hostPorts) 273 } 274 275 // InitAgent initialises the given agent command with additional 276 // arguments as provided. 277 func (s *AgentSuite) InitAgent(c *gc.C, a cmd.Command, args ...string) { 278 args = append([]string{"--data-dir", s.DataDir()}, args...) 279 err := cmdtesting.InitCommand(a, args) 280 c.Assert(err, jc.ErrorIsNil) 281 } 282 283 func (s *AgentSuite) AssertCanOpenState(c *gc.C, tag names.Tag, dataDir string) { 284 config, err := agent.ReadConfig(agent.ConfigPath(dataDir, tag)) 285 c.Assert(err, jc.ErrorIsNil) 286 info, ok := config.MongoInfo() 287 c.Assert(ok, jc.IsTrue) 288 session, err := mongo.DialWithInfo(*info, mongotest.DialOpts()) 289 c.Assert(err, jc.ErrorIsNil) 290 defer session.Close() 291 pool, err := state.OpenStatePool(state.OpenParams{ 292 Clock: clock.WallClock, 293 ControllerTag: config.Controller(), 294 ControllerModelTag: config.Model(), 295 MongoSession: session, 296 NewPolicy: stateenvirons.GetNewPolicyFunc(), 297 }) 298 c.Assert(err, jc.ErrorIsNil) 299 pool.Close() 300 } 301 302 func (s *AgentSuite) AssertCannotOpenState(c *gc.C, tag names.Tag, dataDir string) { 303 config, err := agent.ReadConfig(agent.ConfigPath(dataDir, tag)) 304 c.Assert(err, jc.ErrorIsNil) 305 _, ok := config.MongoInfo() 306 c.Assert(ok, jc.IsFalse) 307 }