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