github.com/recobe182/terraform@v0.8.5-0.20170117231232-49ab22a935b7/command/remote_config_test.go (about) 1 package command 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "testing" 9 10 "github.com/hashicorp/terraform/state" 11 "github.com/hashicorp/terraform/terraform" 12 "github.com/mitchellh/cli" 13 ) 14 15 // Test disabling remote management 16 func TestRemoteConfig_disable(t *testing.T) { 17 tmp, cwd := testCwd(t) 18 defer testFixCwd(t, tmp, cwd) 19 20 // Create remote state file, this should be pulled 21 s := terraform.NewState() 22 s.Serial = 10 23 conf, srv := testRemoteState(t, s, 200) 24 defer srv.Close() 25 26 // Persist local remote state 27 s = terraform.NewState() 28 s.Serial = 5 29 s.Remote = conf 30 31 // Write the state 32 statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename) 33 state := &state.LocalState{Path: statePath} 34 if err := state.WriteState(s); err != nil { 35 t.Fatalf("err: %s", err) 36 } 37 if err := state.PersistState(); err != nil { 38 t.Fatalf("err: %s", err) 39 } 40 41 ui := new(cli.MockUi) 42 c := &RemoteConfigCommand{ 43 Meta: Meta{ 44 ContextOpts: testCtxConfig(testProvider()), 45 Ui: ui, 46 }, 47 } 48 args := []string{"-disable"} 49 if code := c.Run(args); code != 0 { 50 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 51 } 52 53 // Local state file should be removed and the local cache should exist 54 testRemoteLocal(t, true) 55 testRemoteLocalCache(t, false) 56 57 // Check that the state file was updated 58 raw, _ := ioutil.ReadFile(DefaultStateFilename) 59 newState, err := terraform.ReadState(bytes.NewReader(raw)) 60 if err != nil { 61 t.Fatalf("err: %v", err) 62 } 63 64 // Ensure we updated 65 if newState.Remote != nil { 66 t.Fatalf("remote configuration not removed") 67 } 68 } 69 70 // Test disabling remote management without pulling 71 func TestRemoteConfig_disable_noPull(t *testing.T) { 72 tmp, cwd := testCwd(t) 73 defer testFixCwd(t, tmp, cwd) 74 75 // Create remote state file, this should be pulled 76 s := terraform.NewState() 77 s.Serial = 10 78 conf, srv := testRemoteState(t, s, 200) 79 defer srv.Close() 80 81 // Persist local remote state 82 s = terraform.NewState() 83 s.Serial = 5 84 s.Remote = conf 85 86 // Write the state 87 statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename) 88 state := &state.LocalState{Path: statePath} 89 if err := state.WriteState(s); err != nil { 90 t.Fatalf("err: %s", err) 91 } 92 if err := state.PersistState(); err != nil { 93 t.Fatalf("err: %s", err) 94 } 95 96 ui := new(cli.MockUi) 97 c := &RemoteConfigCommand{ 98 Meta: Meta{ 99 ContextOpts: testCtxConfig(testProvider()), 100 Ui: ui, 101 }, 102 } 103 args := []string{"-disable", "-pull=false"} 104 if code := c.Run(args); code != 0 { 105 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 106 } 107 108 // Local state file should be removed and the local cache should exist 109 testRemoteLocal(t, true) 110 testRemoteLocalCache(t, false) 111 112 // Check that the state file was updated 113 raw, _ := ioutil.ReadFile(DefaultStateFilename) 114 newState, err := terraform.ReadState(bytes.NewReader(raw)) 115 if err != nil { 116 t.Fatalf("err: %v", err) 117 } 118 119 if newState.Remote != nil { 120 t.Fatalf("remote configuration not removed") 121 } 122 } 123 124 // Test disabling remote management when not enabled 125 func TestRemoteConfig_disable_notEnabled(t *testing.T) { 126 tmp, cwd := testCwd(t) 127 defer testFixCwd(t, tmp, cwd) 128 129 ui := new(cli.MockUi) 130 c := &RemoteConfigCommand{ 131 Meta: Meta{ 132 ContextOpts: testCtxConfig(testProvider()), 133 Ui: ui, 134 }, 135 } 136 137 args := []string{"-disable"} 138 if code := c.Run(args); code != 1 { 139 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 140 } 141 } 142 143 // Test disabling remote management with a state file in the way 144 func TestRemoteConfig_disable_otherState(t *testing.T) { 145 tmp, cwd := testCwd(t) 146 defer testFixCwd(t, tmp, cwd) 147 148 // Persist local remote state 149 s := terraform.NewState() 150 s.Serial = 5 151 152 // Write the state 153 statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename) 154 state := &state.LocalState{Path: statePath} 155 if err := state.WriteState(s); err != nil { 156 t.Fatalf("err: %s", err) 157 } 158 if err := state.PersistState(); err != nil { 159 t.Fatalf("err: %s", err) 160 } 161 162 // Also put a file at the default path 163 fh, err := os.Create(DefaultStateFilename) 164 if err != nil { 165 t.Fatalf("err: %v", err) 166 } 167 err = terraform.WriteState(s, fh) 168 fh.Close() 169 if err != nil { 170 t.Fatalf("err: %v", err) 171 } 172 173 ui := new(cli.MockUi) 174 c := &RemoteConfigCommand{ 175 Meta: Meta{ 176 ContextOpts: testCtxConfig(testProvider()), 177 Ui: ui, 178 }, 179 } 180 181 args := []string{"-disable"} 182 if code := c.Run(args); code != 1 { 183 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 184 } 185 } 186 187 // Test the case where both managed and non managed state present 188 func TestRemoteConfig_managedAndNonManaged(t *testing.T) { 189 tmp, cwd := testCwd(t) 190 defer testFixCwd(t, tmp, cwd) 191 192 // Persist local remote state 193 s := terraform.NewState() 194 s.Serial = 5 195 196 // Write the state 197 statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename) 198 state := &state.LocalState{Path: statePath} 199 if err := state.WriteState(s); err != nil { 200 t.Fatalf("err: %s", err) 201 } 202 if err := state.PersistState(); err != nil { 203 t.Fatalf("err: %s", err) 204 } 205 206 // Also put a file at the default path 207 fh, err := os.Create(DefaultStateFilename) 208 if err != nil { 209 t.Fatalf("err: %v", err) 210 } 211 err = terraform.WriteState(s, fh) 212 fh.Close() 213 if err != nil { 214 t.Fatalf("err: %v", err) 215 } 216 217 ui := new(cli.MockUi) 218 c := &RemoteConfigCommand{ 219 Meta: Meta{ 220 ContextOpts: testCtxConfig(testProvider()), 221 Ui: ui, 222 }, 223 } 224 225 args := []string{} 226 if code := c.Run(args); code != 1 { 227 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 228 } 229 } 230 231 // Test initializing blank state 232 func TestRemoteConfig_initBlank(t *testing.T) { 233 tmp, cwd := testCwd(t) 234 defer testFixCwd(t, tmp, cwd) 235 236 ui := new(cli.MockUi) 237 c := &RemoteConfigCommand{ 238 Meta: Meta{ 239 ContextOpts: testCtxConfig(testProvider()), 240 Ui: ui, 241 }, 242 } 243 244 args := []string{ 245 "-backend=http", 246 "-backend-config", "address=http://example.com", 247 "-backend-config", "access_token=test", 248 "-pull=false", 249 } 250 if code := c.Run(args); code != 0 { 251 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 252 } 253 254 remotePath := filepath.Join(DefaultDataDir, DefaultStateFilename) 255 ls := &state.LocalState{Path: remotePath} 256 if err := ls.RefreshState(); err != nil { 257 t.Fatalf("err: %s", err) 258 } 259 260 local := ls.State() 261 if local.Remote.Type != "http" { 262 t.Fatalf("Bad: %#v", local.Remote) 263 } 264 if local.Remote.Config["address"] != "http://example.com" { 265 t.Fatalf("Bad: %#v", local.Remote) 266 } 267 if local.Remote.Config["access_token"] != "test" { 268 t.Fatalf("Bad: %#v", local.Remote) 269 } 270 } 271 272 // Test initializing without remote settings 273 func TestRemoteConfig_initBlank_missingRemote(t *testing.T) { 274 tmp, cwd := testCwd(t) 275 defer testFixCwd(t, tmp, cwd) 276 277 ui := new(cli.MockUi) 278 c := &RemoteConfigCommand{ 279 Meta: Meta{ 280 ContextOpts: testCtxConfig(testProvider()), 281 Ui: ui, 282 }, 283 } 284 285 args := []string{} 286 if code := c.Run(args); code != 1 { 287 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 288 } 289 } 290 291 // Test updating remote config 292 func TestRemoteConfig_updateRemote(t *testing.T) { 293 tmp, cwd := testCwd(t) 294 defer testFixCwd(t, tmp, cwd) 295 296 // Persist local remote state 297 s := terraform.NewState() 298 s.Serial = 5 299 s.Remote = &terraform.RemoteState{ 300 Type: "invalid", 301 } 302 303 // Write the state 304 statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename) 305 ls := &state.LocalState{Path: statePath} 306 if err := ls.WriteState(s); err != nil { 307 t.Fatalf("err: %s", err) 308 } 309 if err := ls.PersistState(); err != nil { 310 t.Fatalf("err: %s", err) 311 } 312 313 ui := new(cli.MockUi) 314 c := &RemoteConfigCommand{ 315 Meta: Meta{ 316 ContextOpts: testCtxConfig(testProvider()), 317 Ui: ui, 318 }, 319 } 320 321 args := []string{ 322 "-backend=http", 323 "-backend-config", "address=http://example.com", 324 "-backend-config", "access_token=test", 325 "-pull=false", 326 } 327 if code := c.Run(args); code != 0 { 328 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 329 } 330 331 remotePath := filepath.Join(DefaultDataDir, DefaultStateFilename) 332 ls = &state.LocalState{Path: remotePath} 333 if err := ls.RefreshState(); err != nil { 334 t.Fatalf("err: %s", err) 335 } 336 local := ls.State() 337 338 if local.Remote.Type != "http" { 339 t.Fatalf("Bad: %#v", local.Remote) 340 } 341 if local.Remote.Config["address"] != "http://example.com" { 342 t.Fatalf("Bad: %#v", local.Remote) 343 } 344 if local.Remote.Config["access_token"] != "test" { 345 t.Fatalf("Bad: %#v", local.Remote) 346 } 347 } 348 349 // Test enabling remote state 350 func TestRemoteConfig_enableRemote(t *testing.T) { 351 tmp, cwd := testCwd(t) 352 defer testFixCwd(t, tmp, cwd) 353 354 // Create a non-remote enabled state 355 s := terraform.NewState() 356 s.Serial = 5 357 358 // Add the state at the default path 359 fh, err := os.Create(DefaultStateFilename) 360 if err != nil { 361 t.Fatalf("err: %v", err) 362 } 363 err = terraform.WriteState(s, fh) 364 fh.Close() 365 if err != nil { 366 t.Fatalf("err: %v", err) 367 } 368 369 ui := new(cli.MockUi) 370 c := &RemoteConfigCommand{ 371 Meta: Meta{ 372 ContextOpts: testCtxConfig(testProvider()), 373 Ui: ui, 374 }, 375 } 376 377 args := []string{ 378 "-backend=http", 379 "-backend-config", "address=http://example.com", 380 "-backend-config", "access_token=test", 381 "-pull=false", 382 } 383 if code := c.Run(args); code != 0 { 384 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 385 } 386 387 remotePath := filepath.Join(DefaultDataDir, DefaultStateFilename) 388 ls := &state.LocalState{Path: remotePath} 389 if err := ls.RefreshState(); err != nil { 390 t.Fatalf("err: %s", err) 391 } 392 local := ls.State() 393 394 if local.Remote.Type != "http" { 395 t.Fatalf("Bad: %#v", local.Remote) 396 } 397 if local.Remote.Config["address"] != "http://example.com" { 398 t.Fatalf("Bad: %#v", local.Remote) 399 } 400 if local.Remote.Config["access_token"] != "test" { 401 t.Fatalf("Bad: %#v", local.Remote) 402 } 403 404 // Backup file should exist, state file should not 405 testRemoteLocal(t, false) 406 testRemoteLocalBackup(t, true) 407 } 408 409 func testRemoteLocal(t *testing.T, exists bool) { 410 _, err := os.Stat(DefaultStateFilename) 411 if os.IsNotExist(err) && !exists { 412 return 413 } 414 if err == nil && exists { 415 return 416 } 417 418 t.Fatalf("bad: %#v", err) 419 } 420 421 func testRemoteLocalBackup(t *testing.T, exists bool) { 422 _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension) 423 if os.IsNotExist(err) && !exists { 424 return 425 } 426 if err == nil && exists { 427 return 428 } 429 if err == nil && !exists { 430 t.Fatal("expected local backup to exist") 431 } 432 433 t.Fatalf("bad: %#v", err) 434 } 435 436 func testRemoteLocalCache(t *testing.T, exists bool) { 437 _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)) 438 if os.IsNotExist(err) && !exists { 439 return 440 } 441 if err == nil && exists { 442 return 443 } 444 if err == nil && !exists { 445 t.Fatal("expected local cache to exist") 446 } 447 448 t.Fatalf("bad: %#v", err) 449 }