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