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  }