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  }