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  }