github.com/pmcatominey/terraform@v0.7.0-rc2.0.20160708105029-1401a52a5cc5/builtin/providers/google/resource_compute_url_map.go (about) 1 package google 2 3 import ( 4 "fmt" 5 "log" 6 "strconv" 7 8 "github.com/hashicorp/terraform/helper/schema" 9 "google.golang.org/api/compute/v1" 10 "google.golang.org/api/googleapi" 11 ) 12 13 func resourceComputeUrlMap() *schema.Resource { 14 return &schema.Resource{ 15 Create: resourceComputeUrlMapCreate, 16 Read: resourceComputeUrlMapRead, 17 Update: resourceComputeUrlMapUpdate, 18 Delete: resourceComputeUrlMapDelete, 19 20 Schema: map[string]*schema.Schema{ 21 "default_service": &schema.Schema{ 22 Type: schema.TypeString, 23 Required: true, 24 }, 25 26 "name": &schema.Schema{ 27 Type: schema.TypeString, 28 Required: true, 29 ForceNew: true, 30 }, 31 32 "description": &schema.Schema{ 33 Type: schema.TypeString, 34 Optional: true, 35 }, 36 37 "fingerprint": &schema.Schema{ 38 Type: schema.TypeString, 39 Computed: true, 40 }, 41 42 "host_rule": &schema.Schema{ 43 Type: schema.TypeList, 44 Optional: true, 45 Elem: &schema.Resource{ 46 Schema: map[string]*schema.Schema{ 47 "description": &schema.Schema{ 48 Type: schema.TypeString, 49 Optional: true, 50 }, 51 52 "hosts": &schema.Schema{ 53 Type: schema.TypeList, 54 Required: true, 55 Elem: &schema.Schema{Type: schema.TypeString}, 56 }, 57 58 "path_matcher": &schema.Schema{ 59 Type: schema.TypeString, 60 Required: true, 61 }, 62 }, 63 }, 64 }, 65 66 "id": &schema.Schema{ 67 Type: schema.TypeString, 68 Computed: true, 69 }, 70 71 "path_matcher": &schema.Schema{ 72 Type: schema.TypeList, 73 Optional: true, 74 Elem: &schema.Resource{ 75 Schema: map[string]*schema.Schema{ 76 "default_service": &schema.Schema{ 77 Type: schema.TypeString, 78 Required: true, 79 }, 80 81 "description": &schema.Schema{ 82 Type: schema.TypeString, 83 Optional: true, 84 }, 85 86 "name": &schema.Schema{ 87 Type: schema.TypeString, 88 Required: true, 89 }, 90 91 "path_rule": &schema.Schema{ 92 Type: schema.TypeList, 93 Required: true, 94 Elem: &schema.Resource{ 95 Schema: map[string]*schema.Schema{ 96 "paths": &schema.Schema{ 97 Type: schema.TypeList, 98 Required: true, 99 Elem: &schema.Schema{Type: schema.TypeString}, 100 }, 101 102 "service": &schema.Schema{ 103 Type: schema.TypeString, 104 Required: true, 105 }, 106 }, 107 }, 108 }, 109 }, 110 }, 111 }, 112 113 "project": &schema.Schema{ 114 Type: schema.TypeString, 115 Optional: true, 116 ForceNew: true, 117 }, 118 119 "self_link": &schema.Schema{ 120 Type: schema.TypeString, 121 Computed: true, 122 }, 123 124 "test": &schema.Schema{ 125 Type: schema.TypeList, 126 Optional: true, 127 Elem: &schema.Resource{ 128 Schema: map[string]*schema.Schema{ 129 "description": &schema.Schema{ 130 Type: schema.TypeString, 131 Optional: true, 132 }, 133 134 "host": &schema.Schema{ 135 Type: schema.TypeString, 136 Required: true, 137 }, 138 139 "path": &schema.Schema{ 140 Type: schema.TypeString, 141 Required: true, 142 }, 143 144 "service": &schema.Schema{ 145 Type: schema.TypeString, 146 Required: true, 147 }, 148 }, 149 }, 150 }, 151 }, 152 } 153 } 154 155 func createHostRule(v interface{}) *compute.HostRule { 156 _hostRule := v.(map[string]interface{}) 157 158 _hosts := _hostRule["hosts"].([]interface{}) 159 hosts := make([]string, len(_hosts)) 160 161 for i, v := range _hosts { 162 hosts[i] = v.(string) 163 } 164 165 pathMatcher := _hostRule["path_matcher"].(string) 166 167 hostRule := &compute.HostRule{ 168 Hosts: hosts, 169 PathMatcher: pathMatcher, 170 } 171 172 if v, ok := _hostRule["description"]; ok { 173 hostRule.Description = v.(string) 174 } 175 176 return hostRule 177 } 178 179 func createPathMatcher(v interface{}) *compute.PathMatcher { 180 _pathMatcher := v.(map[string]interface{}) 181 182 _pathRules := _pathMatcher["path_rule"].([]interface{}) 183 pathRules := make([]*compute.PathRule, len(_pathRules)) 184 185 for ip, vp := range _pathRules { 186 _pathRule := vp.(map[string]interface{}) 187 188 _paths := _pathRule["paths"].([]interface{}) 189 paths := make([]string, len(_paths)) 190 191 for ipp, vpp := range _paths { 192 paths[ipp] = vpp.(string) 193 } 194 195 service := _pathRule["service"].(string) 196 197 pathRule := &compute.PathRule{ 198 Paths: paths, 199 Service: service, 200 } 201 202 pathRules[ip] = pathRule 203 } 204 205 name := _pathMatcher["name"].(string) 206 defaultService := _pathMatcher["default_service"].(string) 207 208 pathMatcher := &compute.PathMatcher{ 209 PathRules: pathRules, 210 Name: name, 211 DefaultService: defaultService, 212 } 213 214 if vp, okp := _pathMatcher["description"]; okp { 215 pathMatcher.Description = vp.(string) 216 } 217 218 return pathMatcher 219 } 220 221 func createUrlMapTest(v interface{}) *compute.UrlMapTest { 222 _test := v.(map[string]interface{}) 223 224 host := _test["host"].(string) 225 path := _test["path"].(string) 226 service := _test["service"].(string) 227 228 test := &compute.UrlMapTest{ 229 Host: host, 230 Path: path, 231 Service: service, 232 } 233 234 if vp, okp := _test["description"]; okp { 235 test.Description = vp.(string) 236 } 237 238 return test 239 } 240 241 func resourceComputeUrlMapCreate(d *schema.ResourceData, meta interface{}) error { 242 config := meta.(*Config) 243 244 project, err := getProject(d, config) 245 if err != nil { 246 return err 247 } 248 249 name := d.Get("name").(string) 250 defaultService := d.Get("default_service").(string) 251 252 urlMap := &compute.UrlMap{ 253 Name: name, 254 DefaultService: defaultService, 255 } 256 257 if v, ok := d.GetOk("description"); ok { 258 urlMap.Description = v.(string) 259 } 260 261 _hostRules := d.Get("host_rule").([]interface{}) 262 urlMap.HostRules = make([]*compute.HostRule, len(_hostRules)) 263 264 for i, v := range _hostRules { 265 urlMap.HostRules[i] = createHostRule(v) 266 } 267 268 _pathMatchers := d.Get("path_matcher").([]interface{}) 269 urlMap.PathMatchers = make([]*compute.PathMatcher, len(_pathMatchers)) 270 271 for i, v := range _pathMatchers { 272 urlMap.PathMatchers[i] = createPathMatcher(v) 273 } 274 275 _tests := make([]interface{}, 0) 276 if v, ok := d.GetOk("test"); ok { 277 _tests = v.([]interface{}) 278 } 279 urlMap.Tests = make([]*compute.UrlMapTest, len(_tests)) 280 281 for i, v := range _tests { 282 urlMap.Tests[i] = createUrlMapTest(v) 283 } 284 285 op, err := config.clientCompute.UrlMaps.Insert(project, urlMap).Do() 286 287 if err != nil { 288 return fmt.Errorf("Error, failed to insert Url Map %s: %s", name, err) 289 } 290 291 err = computeOperationWaitGlobal(config, op, "Insert Url Map") 292 293 if err != nil { 294 return fmt.Errorf("Error, failed waitng to insert Url Map %s: %s", name, err) 295 } 296 297 return resourceComputeUrlMapRead(d, meta) 298 } 299 300 func resourceComputeUrlMapRead(d *schema.ResourceData, meta interface{}) error { 301 config := meta.(*Config) 302 303 project, err := getProject(d, config) 304 if err != nil { 305 return err 306 } 307 308 name := d.Get("name").(string) 309 310 urlMap, err := config.clientCompute.UrlMaps.Get(project, name).Do() 311 312 if err != nil { 313 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 314 log.Printf("[WARN] Removing URL Map %q because it's gone", d.Get("name").(string)) 315 // The resource doesn't exist anymore 316 d.SetId("") 317 318 return nil 319 } 320 321 return fmt.Errorf("Error, failed to get Url Map %s: %s", name, err) 322 } 323 324 d.SetId(name) 325 d.Set("self_link", urlMap.SelfLink) 326 d.Set("id", strconv.FormatUint(urlMap.Id, 10)) 327 d.Set("fingerprint", urlMap.Fingerprint) 328 329 hostRuleMap := make(map[string]*compute.HostRule) 330 for _, v := range urlMap.HostRules { 331 hostRuleMap[v.PathMatcher] = v 332 } 333 334 /* Only read host rules into our TF state that we have defined */ 335 _hostRules := d.Get("host_rule").([]interface{}) 336 _newHostRules := make([]interface{}, 0) 337 for _, v := range _hostRules { 338 _hostRule := v.(map[string]interface{}) 339 _pathMatcher := _hostRule["path_matcher"].(string) 340 341 /* Delete local entries that are no longer found on the GCE server */ 342 if hostRule, ok := hostRuleMap[_pathMatcher]; ok { 343 _newHostRule := make(map[string]interface{}) 344 _newHostRule["path_matcher"] = _pathMatcher 345 346 hostsSet := make(map[string]bool) 347 for _, host := range hostRule.Hosts { 348 hostsSet[host] = true 349 } 350 351 /* Only store hosts we are keeping track of */ 352 _newHosts := make([]interface{}, 0) 353 for _, vp := range _hostRule["hosts"].([]interface{}) { 354 if _, okp := hostsSet[vp.(string)]; okp { 355 _newHosts = append(_newHosts, vp) 356 } 357 } 358 359 _newHostRule["hosts"] = _newHosts 360 _newHostRule["description"] = hostRule.Description 361 362 _newHostRules = append(_newHostRules, _newHostRule) 363 } 364 } 365 366 d.Set("host_rule", _newHostRules) 367 368 pathMatcherMap := make(map[string]*compute.PathMatcher) 369 for _, v := range urlMap.PathMatchers { 370 pathMatcherMap[v.Name] = v 371 } 372 373 /* Only read path matchers into our TF state that we have defined */ 374 _pathMatchers := d.Get("path_matcher").([]interface{}) 375 _newPathMatchers := make([]interface{}, 0) 376 for _, v := range _pathMatchers { 377 _pathMatcher := v.(map[string]interface{}) 378 _name := _pathMatcher["name"].(string) 379 380 if pathMatcher, ok := pathMatcherMap[_name]; ok { 381 _newPathMatcher := make(map[string]interface{}) 382 _newPathMatcher["name"] = _name 383 _newPathMatcher["default_service"] = pathMatcher.DefaultService 384 _newPathMatcher["description"] = pathMatcher.Description 385 386 _newPathRules := make([]interface{}, len(pathMatcher.PathRules)) 387 for ip, pathRule := range pathMatcher.PathRules { 388 _newPathRule := make(map[string]interface{}) 389 _newPathRule["service"] = pathRule.Service 390 _paths := make([]interface{}, len(pathRule.Paths)) 391 392 for ipp, vpp := range pathRule.Paths { 393 _paths[ipp] = vpp 394 } 395 396 _newPathRule["paths"] = _paths 397 398 _newPathRules[ip] = _newPathRule 399 } 400 401 _newPathMatcher["path_rule"] = _newPathRules 402 _newPathMatchers = append(_newPathMatchers, _newPathMatcher) 403 } 404 } 405 406 d.Set("path_matcher", _newPathMatchers) 407 408 testMap := make(map[string]*compute.UrlMapTest) 409 for _, v := range urlMap.Tests { 410 testMap[fmt.Sprintf("%s/%s", v.Host, v.Path)] = v 411 } 412 413 _tests := make([]interface{}, 0) 414 /* Only read tests into our TF state that we have defined */ 415 if v, ok := d.GetOk("test"); ok { 416 _tests = v.([]interface{}) 417 } 418 _newTests := make([]interface{}, 0) 419 for _, v := range _tests { 420 _test := v.(map[string]interface{}) 421 _host := _test["host"].(string) 422 _path := _test["path"].(string) 423 424 /* Delete local entries that are no longer found on the GCE server */ 425 if test, ok := testMap[fmt.Sprintf("%s/%s", _host, _path)]; ok { 426 _newTest := make(map[string]interface{}) 427 _newTest["host"] = _host 428 _newTest["path"] = _path 429 _newTest["description"] = test.Description 430 _newTest["service"] = test.Service 431 432 _newTests = append(_newTests, _newTest) 433 } 434 } 435 436 d.Set("test", _newTests) 437 438 return nil 439 } 440 441 func resourceComputeUrlMapUpdate(d *schema.ResourceData, meta interface{}) error { 442 config := meta.(*Config) 443 444 project, err := getProject(d, config) 445 if err != nil { 446 return err 447 } 448 449 name := d.Get("name").(string) 450 urlMap, err := config.clientCompute.UrlMaps.Get(project, name).Do() 451 if err != nil { 452 return fmt.Errorf("Error, failed to get Url Map %s: %s", name, err) 453 } 454 455 urlMap.DefaultService = d.Get("default_service").(string) 456 457 if v, ok := d.GetOk("description"); ok { 458 urlMap.Description = v.(string) 459 } 460 461 if d.HasChange("host_rule") { 462 _oldHostRules, _newHostRules := d.GetChange("host_rule") 463 _oldHostRulesMap := make(map[string]interface{}) 464 _newHostRulesMap := make(map[string]interface{}) 465 466 for _, v := range _oldHostRules.([]interface{}) { 467 _hostRule := v.(map[string]interface{}) 468 _oldHostRulesMap[_hostRule["path_matcher"].(string)] = v 469 } 470 471 for _, v := range _newHostRules.([]interface{}) { 472 _hostRule := v.(map[string]interface{}) 473 _newHostRulesMap[_hostRule["path_matcher"].(string)] = v 474 } 475 476 newHostRules := make([]*compute.HostRule, 0) 477 /* Decide which host rules to keep */ 478 for _, v := range urlMap.HostRules { 479 /* If it's in the old state, we have ownership over the host rule */ 480 if vOld, ok := _oldHostRulesMap[v.PathMatcher]; ok { 481 if vNew, ok := _newHostRulesMap[v.PathMatcher]; ok { 482 /* Adjust for any changes made to this rule */ 483 _newHostRule := vNew.(map[string]interface{}) 484 _oldHostRule := vOld.(map[string]interface{}) 485 _newHostsSet := make(map[string]bool) 486 _oldHostsSet := make(map[string]bool) 487 488 hostRule := &compute.HostRule{ 489 PathMatcher: v.PathMatcher, 490 } 491 492 for _, v := range _newHostRule["hosts"].([]interface{}) { 493 _newHostsSet[v.(string)] = true 494 } 495 496 for _, v := range _oldHostRule["hosts"].([]interface{}) { 497 _oldHostsSet[v.(string)] = true 498 } 499 500 /* Only add hosts that have been added locally or are new, 501 * not touching those from the GCE server state */ 502 for _, host := range v.Hosts { 503 _, okNew := _newHostsSet[host] 504 _, okOld := _oldHostsSet[host] 505 506 /* Drop deleted hosts */ 507 if okOld && !okNew { 508 continue 509 } 510 511 hostRule.Hosts = append(hostRule.Hosts, host) 512 513 /* Kep track of the fact that this host was added */ 514 delete(_newHostsSet, host) 515 } 516 517 /* Now add in the brand new entries */ 518 for host, _ := range _oldHostsSet { 519 hostRule.Hosts = append(hostRule.Hosts, host) 520 } 521 522 if v, ok := _newHostRule["description"]; ok { 523 hostRule.Description = v.(string) 524 } 525 526 newHostRules = append(newHostRules, hostRule) 527 528 /* Record that we've include this host rule */ 529 delete(_newHostRulesMap, v.PathMatcher) 530 } else { 531 /* It's been deleted */ 532 continue 533 } 534 } else { 535 if vNew, ok := _newHostRulesMap[v.PathMatcher]; ok { 536 newHostRules = append(newHostRules, createHostRule(vNew)) 537 538 /* Record that we've include this host rule */ 539 delete(_newHostRulesMap, v.PathMatcher) 540 } else { 541 /* It wasn't created or modified locally */ 542 newHostRules = append(newHostRules, v) 543 } 544 } 545 } 546 547 /* Record brand new host rules (ones not deleted above) */ 548 for _, v := range _newHostRulesMap { 549 newHostRules = append(newHostRules, createHostRule(v)) 550 } 551 552 urlMap.HostRules = newHostRules 553 } 554 555 if d.HasChange("path_matcher") { 556 _oldPathMatchers, _newPathMatchers := d.GetChange("path_matcher") 557 _oldPathMatchersMap := make(map[string]interface{}) 558 _newPathMatchersMap := make(map[string]interface{}) 559 560 for _, v := range _oldPathMatchers.([]interface{}) { 561 _pathMatcher := v.(map[string]interface{}) 562 _oldPathMatchersMap[_pathMatcher["name"].(string)] = v 563 } 564 565 for _, v := range _newPathMatchers.([]interface{}) { 566 _pathMatcher := v.(map[string]interface{}) 567 _newPathMatchersMap[_pathMatcher["name"].(string)] = v 568 } 569 570 newPathMatchers := make([]*compute.PathMatcher, 0) 571 /* Decide which path matchers to keep */ 572 for _, v := range urlMap.PathMatchers { 573 /* If it's in the old state, we have ownership over the host rule */ 574 _, okOld := _oldPathMatchersMap[v.Name] 575 vNew, okNew := _newPathMatchersMap[v.Name] 576 577 /* Drop deleted entries */ 578 if okOld && !okNew { 579 continue 580 } 581 582 /* Don't change entries that don't belong to us */ 583 if !okNew { 584 newPathMatchers = append(newPathMatchers, v) 585 } else { 586 newPathMatchers = append(newPathMatchers, createPathMatcher(vNew)) 587 588 delete(_newPathMatchersMap, v.Name) 589 } 590 } 591 592 /* Record brand new host rules */ 593 for _, v := range _newPathMatchersMap { 594 newPathMatchers = append(newPathMatchers, createPathMatcher(v)) 595 } 596 597 urlMap.PathMatchers = newPathMatchers 598 } 599 600 if d.HasChange("tests") { 601 _oldTests, _newTests := d.GetChange("path_matcher") 602 _oldTestsMap := make(map[string]interface{}) 603 _newTestsMap := make(map[string]interface{}) 604 605 for _, v := range _oldTests.([]interface{}) { 606 _test := v.(map[string]interface{}) 607 ident := fmt.Sprintf("%s/%s", _test["host"].(string), _test["path"].(string)) 608 _oldTestsMap[ident] = v 609 } 610 611 for _, v := range _newTests.([]interface{}) { 612 _test := v.(map[string]interface{}) 613 ident := fmt.Sprintf("%s/%s", _test["host"].(string), _test["path"].(string)) 614 _newTestsMap[ident] = v 615 } 616 617 newTests := make([]*compute.UrlMapTest, 0) 618 /* Decide which path matchers to keep */ 619 for _, v := range urlMap.Tests { 620 ident := fmt.Sprintf("%s/%s", v.Host, v.Path) 621 /* If it's in the old state, we have ownership over the host rule */ 622 _, okOld := _oldTestsMap[ident] 623 vNew, okNew := _newTestsMap[ident] 624 625 /* Drop deleted entries */ 626 if okOld && !okNew { 627 continue 628 } 629 630 /* Don't change entries that don't belong to us */ 631 if !okNew { 632 newTests = append(newTests, v) 633 } else { 634 newTests = append(newTests, createUrlMapTest(vNew)) 635 636 delete(_newTestsMap, ident) 637 } 638 } 639 640 /* Record brand new host rules */ 641 for _, v := range _newTestsMap { 642 newTests = append(newTests, createUrlMapTest(v)) 643 } 644 645 urlMap.Tests = newTests 646 } 647 648 op, err := config.clientCompute.UrlMaps.Update(project, urlMap.Name, urlMap).Do() 649 650 if err != nil { 651 return fmt.Errorf("Error, failed to update Url Map %s: %s", name, err) 652 } 653 654 err = computeOperationWaitGlobal(config, op, "Update Url Map") 655 656 if err != nil { 657 return fmt.Errorf("Error, failed waitng to update Url Map %s: %s", name, err) 658 } 659 660 return resourceComputeUrlMapRead(d, meta) 661 } 662 663 func resourceComputeUrlMapDelete(d *schema.ResourceData, meta interface{}) error { 664 config := meta.(*Config) 665 666 project, err := getProject(d, config) 667 if err != nil { 668 return err 669 } 670 671 name := d.Get("name").(string) 672 673 op, err := config.clientCompute.UrlMaps.Delete(project, name).Do() 674 675 if err != nil { 676 return fmt.Errorf("Error, failed to delete Url Map %s: %s", name, err) 677 } 678 679 err = computeOperationWaitGlobal(config, op, "Delete Url Map") 680 681 if err != nil { 682 return fmt.Errorf("Error, failed waitng to delete Url Map %s: %s", name, err) 683 } 684 685 return nil 686 }