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