github.com/quite/nomad@v0.8.6/command/agent/retry_join_test.go (about) 1 package agent 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "os" 8 "testing" 9 "time" 10 11 "github.com/hashicorp/nomad/testutil" 12 "github.com/mitchellh/cli" 13 "github.com/stretchr/testify/require" 14 ) 15 16 type MockDiscover struct { 17 ReceivedAddrs string 18 } 19 20 const stubAddress = "127.0.0.1" 21 22 func (m *MockDiscover) Addrs(s string, l *log.Logger) ([]string, error) { 23 m.ReceivedAddrs = s 24 return []string{stubAddress}, nil 25 } 26 func (m *MockDiscover) Help() string { return "" } 27 func (m *MockDiscover) Names() []string { 28 return []string{""} 29 } 30 31 func TestRetryJoin_Integration(t *testing.T) { 32 t.Parallel() 33 34 // Create two agents and have one retry join the other 35 agent := NewTestAgent(t, t.Name(), nil) 36 defer agent.Shutdown() 37 38 agent2 := NewTestAgent(t, t.Name(), func(c *Config) { 39 c.NodeName = "foo" 40 if c.Server.ServerJoin == nil { 41 c.Server.ServerJoin = &ServerJoin{} 42 } 43 c.Server.ServerJoin.RetryJoin = []string{agent.Config.normalizedAddrs.Serf} 44 c.Server.ServerJoin.RetryInterval = 1 * time.Second 45 }) 46 defer agent2.Shutdown() 47 48 // Create a fake command and have it wrap the second agent and run the retry 49 // join handler 50 cmd := &Command{ 51 Ui: &cli.BasicUi{ 52 Reader: os.Stdin, 53 Writer: os.Stdout, 54 ErrorWriter: os.Stderr, 55 }, 56 agent: agent2.Agent, 57 } 58 59 if err := cmd.handleRetryJoin(agent2.Config); err != nil { 60 t.Fatalf("handleRetryJoin failed: %v", err) 61 } 62 63 // Ensure the retry join occurred. 64 testutil.WaitForResult(func() (bool, error) { 65 mem := agent.server.Members() 66 if len(mem) != 2 { 67 return false, fmt.Errorf("bad :%#v", mem) 68 } 69 return true, nil 70 }, func(err error) { 71 t.Fatalf(err.Error()) 72 }) 73 } 74 75 func TestRetryJoin_Server_NonCloud(t *testing.T) { 76 t.Parallel() 77 require := require.New(t) 78 79 serverJoin := &ServerJoin{ 80 RetryMaxAttempts: 1, 81 RetryJoin: []string{"127.0.0.1"}, 82 } 83 84 var output []string 85 86 mockJoin := func(s []string) (int, error) { 87 output = s 88 return 0, nil 89 } 90 91 joiner := retryJoiner{ 92 discover: &MockDiscover{}, 93 serverJoin: mockJoin, 94 serverEnabled: true, 95 logger: log.New(ioutil.Discard, "", 0), 96 errCh: make(chan struct{}), 97 } 98 99 joiner.RetryJoin(serverJoin) 100 101 require.Equal(1, len(output)) 102 require.Equal(stubAddress, output[0]) 103 } 104 105 func TestRetryJoin_Server_Cloud(t *testing.T) { 106 t.Parallel() 107 require := require.New(t) 108 109 serverJoin := &ServerJoin{ 110 RetryMaxAttempts: 1, 111 RetryJoin: []string{"provider=aws, tag_value=foo"}, 112 } 113 114 var output []string 115 116 mockJoin := func(s []string) (int, error) { 117 output = s 118 return 0, nil 119 } 120 121 mockDiscover := &MockDiscover{} 122 joiner := retryJoiner{ 123 discover: mockDiscover, 124 serverJoin: mockJoin, 125 serverEnabled: true, 126 logger: log.New(ioutil.Discard, "", 0), 127 errCh: make(chan struct{}), 128 } 129 130 joiner.RetryJoin(serverJoin) 131 132 require.Equal(1, len(output)) 133 require.Equal("provider=aws, tag_value=foo", mockDiscover.ReceivedAddrs) 134 require.Equal(stubAddress, output[0]) 135 } 136 137 func TestRetryJoin_Server_MixedProvider(t *testing.T) { 138 t.Parallel() 139 require := require.New(t) 140 141 serverJoin := &ServerJoin{ 142 RetryMaxAttempts: 1, 143 RetryJoin: []string{"provider=aws, tag_value=foo", "127.0.0.1"}, 144 } 145 146 var output []string 147 148 mockJoin := func(s []string) (int, error) { 149 output = s 150 return 0, nil 151 } 152 153 mockDiscover := &MockDiscover{} 154 joiner := retryJoiner{ 155 discover: mockDiscover, 156 serverJoin: mockJoin, 157 serverEnabled: true, 158 logger: log.New(ioutil.Discard, "", 0), 159 errCh: make(chan struct{}), 160 } 161 162 joiner.RetryJoin(serverJoin) 163 164 require.Equal(2, len(output)) 165 require.Equal("provider=aws, tag_value=foo", mockDiscover.ReceivedAddrs) 166 require.Equal(stubAddress, output[0]) 167 } 168 169 func TestRetryJoin_Client(t *testing.T) { 170 t.Parallel() 171 require := require.New(t) 172 173 serverJoin := &ServerJoin{ 174 RetryMaxAttempts: 1, 175 RetryJoin: []string{"127.0.0.1"}, 176 } 177 178 var output []string 179 180 mockJoin := func(s []string) (int, error) { 181 output = s 182 return 0, nil 183 } 184 185 joiner := retryJoiner{ 186 discover: &MockDiscover{}, 187 clientJoin: mockJoin, 188 clientEnabled: true, 189 logger: log.New(ioutil.Discard, "", 0), 190 errCh: make(chan struct{}), 191 } 192 193 joiner.RetryJoin(serverJoin) 194 195 require.Equal(1, len(output)) 196 require.Equal(stubAddress, output[0]) 197 } 198 199 func TestRetryJoin_Validate(t *testing.T) { 200 t.Parallel() 201 type validateExpect struct { 202 config *Config 203 isValid bool 204 reason string 205 } 206 207 scenarios := []*validateExpect{ 208 { 209 config: &Config{ 210 Server: &ServerConfig{ 211 ServerJoin: &ServerJoin{ 212 RetryJoin: []string{"127.0.0.1"}, 213 RetryMaxAttempts: 0, 214 RetryInterval: 0, 215 StartJoin: []string{}, 216 }, 217 RetryJoin: []string{"127.0.0.1"}, 218 RetryMaxAttempts: 0, 219 RetryInterval: 0, 220 StartJoin: []string{}, 221 }, 222 }, 223 isValid: false, 224 reason: "server_join cannot be defined if retry_join is defined on the server stanza", 225 }, 226 { 227 config: &Config{ 228 Server: &ServerConfig{ 229 ServerJoin: &ServerJoin{ 230 RetryJoin: []string{"127.0.0.1"}, 231 RetryMaxAttempts: 0, 232 RetryInterval: 0, 233 StartJoin: []string{}, 234 }, 235 StartJoin: []string{"127.0.0.1"}, 236 RetryMaxAttempts: 0, 237 RetryInterval: 0, 238 RetryJoin: []string{}, 239 }, 240 }, 241 isValid: false, 242 reason: "server_join cannot be defined if start_join is defined on the server stanza", 243 }, 244 { 245 config: &Config{ 246 Server: &ServerConfig{ 247 ServerJoin: &ServerJoin{ 248 RetryJoin: []string{"127.0.0.1"}, 249 RetryMaxAttempts: 0, 250 RetryInterval: 0, 251 StartJoin: []string{}, 252 }, 253 StartJoin: []string{}, 254 RetryMaxAttempts: 1, 255 RetryInterval: 0, 256 RetryJoin: []string{}, 257 }, 258 }, 259 isValid: false, 260 reason: "server_join cannot be defined if retry_max_attempts is defined on the server stanza", 261 }, 262 { 263 config: &Config{ 264 Server: &ServerConfig{ 265 ServerJoin: &ServerJoin{ 266 RetryJoin: []string{"127.0.0.1"}, 267 RetryMaxAttempts: 0, 268 RetryInterval: time.Duration(1), 269 StartJoin: []string{}, 270 }, 271 StartJoin: []string{}, 272 RetryMaxAttempts: 0, 273 RetryInterval: 3 * time.Second, 274 RetryJoin: []string{}, 275 }, 276 }, 277 isValid: false, 278 reason: "server_join cannot be defined if retry_interval is defined on the server stanza", 279 }, 280 { 281 config: &Config{ 282 Server: &ServerConfig{ 283 ServerJoin: &ServerJoin{ 284 RetryJoin: []string{"127.0.0.1"}, 285 RetryMaxAttempts: 0, 286 RetryInterval: 0, 287 StartJoin: []string{"127.0.0.1"}, 288 }, 289 }, 290 }, 291 isValid: false, 292 reason: "start_join and retry_join should not both be defined", 293 }, 294 { 295 config: &Config{ 296 Client: &ClientConfig{ 297 ServerJoin: &ServerJoin{ 298 RetryJoin: []string{}, 299 RetryMaxAttempts: 0, 300 RetryInterval: 0, 301 StartJoin: []string{"127.0.0.1"}, 302 }, 303 }, 304 }, 305 isValid: false, 306 reason: "start_join should not be defined on the client", 307 }, 308 { 309 config: &Config{ 310 Client: &ClientConfig{ 311 ServerJoin: &ServerJoin{ 312 RetryJoin: []string{"127.0.0.1"}, 313 RetryMaxAttempts: 0, 314 RetryInterval: 0, 315 }, 316 }, 317 }, 318 isValid: true, 319 reason: "client server_join should be valid", 320 }, 321 { 322 config: &Config{ 323 Server: &ServerConfig{ 324 ServerJoin: &ServerJoin{ 325 RetryJoin: []string{"127.0.0.1"}, 326 RetryMaxAttempts: 1, 327 RetryInterval: 1, 328 StartJoin: []string{}, 329 }, 330 }, 331 }, 332 isValid: true, 333 reason: "server server_join should be valid", 334 }, 335 } 336 337 joiner := retryJoiner{} 338 for _, scenario := range scenarios { 339 t.Run(scenario.reason, func(t *testing.T) { 340 err := joiner.Validate(scenario.config) 341 if scenario.isValid { 342 require.NoError(t, err) 343 } else { 344 require.Error(t, err) 345 } 346 }) 347 } 348 }