703 lines
18 KiB
Go
703 lines
18 KiB
Go
package google
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strconv"
|
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
"google.golang.org/api/compute/v1"
|
|
"google.golang.org/api/googleapi"
|
|
)
|
|
|
|
func resourceComputeUrlMap() *schema.Resource {
|
|
return &schema.Resource{
|
|
Create: resourceComputeUrlMapCreate,
|
|
Read: resourceComputeUrlMapRead,
|
|
Update: resourceComputeUrlMapUpdate,
|
|
Delete: resourceComputeUrlMapDelete,
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
"default_service": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"description": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"fingerprint": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
},
|
|
|
|
"host_rule": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
// TODO(evandbrown): Enable when lists support validation
|
|
//ValidateFunc: validateHostRules,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"description": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"hosts": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Required: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
|
|
"path_matcher": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"id": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
},
|
|
|
|
"path_matcher": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"default_service": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"description": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"path_rule": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Required: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"paths": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Required: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
|
|
"service": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"project": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"self_link": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
},
|
|
|
|
"test": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"description": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"host": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"path": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"service": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func createHostRule(v interface{}) *compute.HostRule {
|
|
_hostRule := v.(map[string]interface{})
|
|
|
|
_hosts := _hostRule["hosts"].([]interface{})
|
|
hosts := make([]string, len(_hosts))
|
|
|
|
for i, v := range _hosts {
|
|
hosts[i] = v.(string)
|
|
}
|
|
|
|
pathMatcher := _hostRule["path_matcher"].(string)
|
|
|
|
hostRule := &compute.HostRule{
|
|
Hosts: hosts,
|
|
PathMatcher: pathMatcher,
|
|
}
|
|
|
|
if v, ok := _hostRule["description"]; ok {
|
|
hostRule.Description = v.(string)
|
|
}
|
|
|
|
return hostRule
|
|
}
|
|
|
|
func createPathMatcher(v interface{}) *compute.PathMatcher {
|
|
_pathMatcher := v.(map[string]interface{})
|
|
|
|
_pathRules := _pathMatcher["path_rule"].([]interface{})
|
|
pathRules := make([]*compute.PathRule, len(_pathRules))
|
|
|
|
for ip, vp := range _pathRules {
|
|
_pathRule := vp.(map[string]interface{})
|
|
|
|
_paths := _pathRule["paths"].([]interface{})
|
|
paths := make([]string, len(_paths))
|
|
|
|
for ipp, vpp := range _paths {
|
|
paths[ipp] = vpp.(string)
|
|
}
|
|
|
|
service := _pathRule["service"].(string)
|
|
|
|
pathRule := &compute.PathRule{
|
|
Paths: paths,
|
|
Service: service,
|
|
}
|
|
|
|
pathRules[ip] = pathRule
|
|
}
|
|
|
|
name := _pathMatcher["name"].(string)
|
|
defaultService := _pathMatcher["default_service"].(string)
|
|
|
|
pathMatcher := &compute.PathMatcher{
|
|
PathRules: pathRules,
|
|
Name: name,
|
|
DefaultService: defaultService,
|
|
}
|
|
|
|
if vp, okp := _pathMatcher["description"]; okp {
|
|
pathMatcher.Description = vp.(string)
|
|
}
|
|
|
|
return pathMatcher
|
|
}
|
|
|
|
func createUrlMapTest(v interface{}) *compute.UrlMapTest {
|
|
_test := v.(map[string]interface{})
|
|
|
|
host := _test["host"].(string)
|
|
path := _test["path"].(string)
|
|
service := _test["service"].(string)
|
|
|
|
test := &compute.UrlMapTest{
|
|
Host: host,
|
|
Path: path,
|
|
Service: service,
|
|
}
|
|
|
|
if vp, okp := _test["description"]; okp {
|
|
test.Description = vp.(string)
|
|
}
|
|
|
|
return test
|
|
}
|
|
|
|
func resourceComputeUrlMapCreate(d *schema.ResourceData, meta interface{}) error {
|
|
config := meta.(*Config)
|
|
|
|
project, err := getProject(d, config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
name := d.Get("name").(string)
|
|
defaultService := d.Get("default_service").(string)
|
|
|
|
urlMap := &compute.UrlMap{
|
|
Name: name,
|
|
DefaultService: defaultService,
|
|
}
|
|
|
|
if v, ok := d.GetOk("description"); ok {
|
|
urlMap.Description = v.(string)
|
|
}
|
|
|
|
_hostRules := d.Get("host_rule").(*schema.Set)
|
|
urlMap.HostRules = make([]*compute.HostRule, _hostRules.Len())
|
|
|
|
for i, v := range _hostRules.List() {
|
|
urlMap.HostRules[i] = createHostRule(v)
|
|
}
|
|
|
|
_pathMatchers := d.Get("path_matcher").([]interface{})
|
|
urlMap.PathMatchers = make([]*compute.PathMatcher, len(_pathMatchers))
|
|
|
|
for i, v := range _pathMatchers {
|
|
urlMap.PathMatchers[i] = createPathMatcher(v)
|
|
}
|
|
|
|
_tests := make([]interface{}, 0)
|
|
if v, ok := d.GetOk("test"); ok {
|
|
_tests = v.([]interface{})
|
|
}
|
|
urlMap.Tests = make([]*compute.UrlMapTest, len(_tests))
|
|
|
|
for i, v := range _tests {
|
|
urlMap.Tests[i] = createUrlMapTest(v)
|
|
}
|
|
|
|
op, err := config.clientCompute.UrlMaps.Insert(project, urlMap).Do()
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error, failed to insert Url Map %s: %s", name, err)
|
|
}
|
|
|
|
err = computeOperationWaitGlobal(config, op, project, "Insert Url Map")
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error, failed waitng to insert Url Map %s: %s", name, err)
|
|
}
|
|
|
|
return resourceComputeUrlMapRead(d, meta)
|
|
}
|
|
|
|
func resourceComputeUrlMapRead(d *schema.ResourceData, meta interface{}) error {
|
|
config := meta.(*Config)
|
|
|
|
project, err := getProject(d, config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
name := d.Get("name").(string)
|
|
|
|
urlMap, err := config.clientCompute.UrlMaps.Get(project, name).Do()
|
|
|
|
if err != nil {
|
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
|
log.Printf("[WARN] Removing URL Map %q because it's gone", d.Get("name").(string))
|
|
// The resource doesn't exist anymore
|
|
d.SetId("")
|
|
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("Error, failed to get Url Map %s: %s", name, err)
|
|
}
|
|
|
|
d.SetId(name)
|
|
d.Set("self_link", urlMap.SelfLink)
|
|
d.Set("id", strconv.FormatUint(urlMap.Id, 10))
|
|
d.Set("fingerprint", urlMap.Fingerprint)
|
|
|
|
hostRuleMap := make(map[string]*compute.HostRule)
|
|
for _, v := range urlMap.HostRules {
|
|
hostRuleMap[v.PathMatcher] = v
|
|
}
|
|
|
|
/* Only read host rules into our TF state that we have defined */
|
|
_hostRules := d.Get("host_rule").(*schema.Set).List()
|
|
_newHostRules := make([]interface{}, 0)
|
|
for _, v := range _hostRules {
|
|
_hostRule := v.(map[string]interface{})
|
|
_pathMatcher := _hostRule["path_matcher"].(string)
|
|
|
|
/* Delete local entries that are no longer found on the GCE server */
|
|
if hostRule, ok := hostRuleMap[_pathMatcher]; ok {
|
|
_newHostRule := make(map[string]interface{})
|
|
_newHostRule["path_matcher"] = _pathMatcher
|
|
|
|
hostsSet := make(map[string]bool)
|
|
for _, host := range hostRule.Hosts {
|
|
hostsSet[host] = true
|
|
}
|
|
|
|
/* Only store hosts we are keeping track of */
|
|
_newHosts := make([]interface{}, 0)
|
|
for _, vp := range _hostRule["hosts"].([]interface{}) {
|
|
if _, okp := hostsSet[vp.(string)]; okp {
|
|
_newHosts = append(_newHosts, vp)
|
|
}
|
|
}
|
|
|
|
_newHostRule["hosts"] = _newHosts
|
|
_newHostRule["description"] = hostRule.Description
|
|
|
|
_newHostRules = append(_newHostRules, _newHostRule)
|
|
}
|
|
}
|
|
|
|
d.Set("host_rule", _newHostRules)
|
|
|
|
pathMatcherMap := make(map[string]*compute.PathMatcher)
|
|
for _, v := range urlMap.PathMatchers {
|
|
pathMatcherMap[v.Name] = v
|
|
}
|
|
|
|
/* Only read path matchers into our TF state that we have defined */
|
|
_pathMatchers := d.Get("path_matcher").([]interface{})
|
|
_newPathMatchers := make([]interface{}, 0)
|
|
for _, v := range _pathMatchers {
|
|
_pathMatcher := v.(map[string]interface{})
|
|
_name := _pathMatcher["name"].(string)
|
|
|
|
if pathMatcher, ok := pathMatcherMap[_name]; ok {
|
|
_newPathMatcher := make(map[string]interface{})
|
|
_newPathMatcher["name"] = _name
|
|
_newPathMatcher["default_service"] = pathMatcher.DefaultService
|
|
_newPathMatcher["description"] = pathMatcher.Description
|
|
|
|
_newPathRules := make([]interface{}, len(pathMatcher.PathRules))
|
|
for ip, pathRule := range pathMatcher.PathRules {
|
|
_newPathRule := make(map[string]interface{})
|
|
_newPathRule["service"] = pathRule.Service
|
|
_paths := make([]interface{}, len(pathRule.Paths))
|
|
|
|
for ipp, vpp := range pathRule.Paths {
|
|
_paths[ipp] = vpp
|
|
}
|
|
|
|
_newPathRule["paths"] = _paths
|
|
|
|
_newPathRules[ip] = _newPathRule
|
|
}
|
|
|
|
_newPathMatcher["path_rule"] = _newPathRules
|
|
_newPathMatchers = append(_newPathMatchers, _newPathMatcher)
|
|
}
|
|
}
|
|
|
|
d.Set("path_matcher", _newPathMatchers)
|
|
|
|
testMap := make(map[string]*compute.UrlMapTest)
|
|
for _, v := range urlMap.Tests {
|
|
testMap[fmt.Sprintf("%s/%s", v.Host, v.Path)] = v
|
|
}
|
|
|
|
_tests := make([]interface{}, 0)
|
|
/* Only read tests into our TF state that we have defined */
|
|
if v, ok := d.GetOk("test"); ok {
|
|
_tests = v.([]interface{})
|
|
}
|
|
_newTests := make([]interface{}, 0)
|
|
for _, v := range _tests {
|
|
_test := v.(map[string]interface{})
|
|
_host := _test["host"].(string)
|
|
_path := _test["path"].(string)
|
|
|
|
/* Delete local entries that are no longer found on the GCE server */
|
|
if test, ok := testMap[fmt.Sprintf("%s/%s", _host, _path)]; ok {
|
|
_newTest := make(map[string]interface{})
|
|
_newTest["host"] = _host
|
|
_newTest["path"] = _path
|
|
_newTest["description"] = test.Description
|
|
_newTest["service"] = test.Service
|
|
|
|
_newTests = append(_newTests, _newTest)
|
|
}
|
|
}
|
|
|
|
d.Set("test", _newTests)
|
|
|
|
return nil
|
|
}
|
|
|
|
func resourceComputeUrlMapUpdate(d *schema.ResourceData, meta interface{}) error {
|
|
config := meta.(*Config)
|
|
|
|
project, err := getProject(d, config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
name := d.Get("name").(string)
|
|
urlMap, err := config.clientCompute.UrlMaps.Get(project, name).Do()
|
|
if err != nil {
|
|
return fmt.Errorf("Error, failed to get Url Map %s: %s", name, err)
|
|
}
|
|
|
|
urlMap.DefaultService = d.Get("default_service").(string)
|
|
|
|
if v, ok := d.GetOk("description"); ok {
|
|
urlMap.Description = v.(string)
|
|
}
|
|
|
|
if d.HasChange("host_rule") {
|
|
_oldHostRules, _newHostRules := d.GetChange("host_rule")
|
|
_oldHostRulesMap := make(map[string]interface{})
|
|
_newHostRulesMap := make(map[string]interface{})
|
|
|
|
for _, v := range _oldHostRules.(*schema.Set).List() {
|
|
_hostRule := v.(map[string]interface{})
|
|
_oldHostRulesMap[_hostRule["path_matcher"].(string)] = v
|
|
}
|
|
|
|
for _, v := range _newHostRules.(*schema.Set).List() {
|
|
_hostRule := v.(map[string]interface{})
|
|
_newHostRulesMap[_hostRule["path_matcher"].(string)] = v
|
|
}
|
|
|
|
newHostRules := make([]*compute.HostRule, 0)
|
|
/* Decide which host rules to keep */
|
|
for _, v := range urlMap.HostRules {
|
|
/* If it's in the old state, we have ownership over the host rule */
|
|
if vOld, ok := _oldHostRulesMap[v.PathMatcher]; ok {
|
|
if vNew, ok := _newHostRulesMap[v.PathMatcher]; ok {
|
|
/* Adjust for any changes made to this rule */
|
|
_newHostRule := vNew.(map[string]interface{})
|
|
_oldHostRule := vOld.(map[string]interface{})
|
|
_newHostsSet := make(map[string]bool)
|
|
_oldHostsSet := make(map[string]bool)
|
|
|
|
hostRule := &compute.HostRule{
|
|
PathMatcher: v.PathMatcher,
|
|
}
|
|
|
|
for _, v := range _newHostRule["hosts"].([]interface{}) {
|
|
_newHostsSet[v.(string)] = true
|
|
}
|
|
|
|
for _, v := range _oldHostRule["hosts"].([]interface{}) {
|
|
_oldHostsSet[v.(string)] = true
|
|
}
|
|
|
|
/* Only add hosts that have been added locally or are new,
|
|
* not touching those from the GCE server state */
|
|
for _, host := range v.Hosts {
|
|
_, okNew := _newHostsSet[host]
|
|
_, okOld := _oldHostsSet[host]
|
|
|
|
/* Drop deleted hosts */
|
|
if okOld && !okNew {
|
|
continue
|
|
}
|
|
|
|
hostRule.Hosts = append(hostRule.Hosts, host)
|
|
|
|
/* Kep track of the fact that this host was added */
|
|
delete(_newHostsSet, host)
|
|
}
|
|
|
|
/* Now add in the brand new entries */
|
|
for host, _ := range _newHostsSet {
|
|
hostRule.Hosts = append(hostRule.Hosts, host)
|
|
}
|
|
|
|
if v, ok := _newHostRule["description"]; ok {
|
|
hostRule.Description = v.(string)
|
|
}
|
|
|
|
newHostRules = append(newHostRules, hostRule)
|
|
|
|
/* Record that we've include this host rule */
|
|
delete(_newHostRulesMap, v.PathMatcher)
|
|
} else {
|
|
/* It's been deleted */
|
|
continue
|
|
}
|
|
} else {
|
|
if vNew, ok := _newHostRulesMap[v.PathMatcher]; ok {
|
|
newHostRules = append(newHostRules, createHostRule(vNew))
|
|
|
|
/* Record that we've include this host rule */
|
|
delete(_newHostRulesMap, v.PathMatcher)
|
|
} else {
|
|
/* It wasn't created or modified locally */
|
|
newHostRules = append(newHostRules, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Record brand new host rules (ones not deleted above) */
|
|
for _, v := range _newHostRulesMap {
|
|
newHostRules = append(newHostRules, createHostRule(v))
|
|
}
|
|
|
|
urlMap.HostRules = newHostRules
|
|
}
|
|
|
|
if d.HasChange("path_matcher") {
|
|
_oldPathMatchers, _newPathMatchers := d.GetChange("path_matcher")
|
|
_oldPathMatchersMap := make(map[string]interface{})
|
|
_newPathMatchersMap := make(map[string]interface{})
|
|
|
|
for _, v := range _oldPathMatchers.([]interface{}) {
|
|
_pathMatcher := v.(map[string]interface{})
|
|
_oldPathMatchersMap[_pathMatcher["name"].(string)] = v
|
|
}
|
|
|
|
for _, v := range _newPathMatchers.([]interface{}) {
|
|
_pathMatcher := v.(map[string]interface{})
|
|
_newPathMatchersMap[_pathMatcher["name"].(string)] = v
|
|
}
|
|
|
|
newPathMatchers := make([]*compute.PathMatcher, 0)
|
|
/* Decide which path matchers to keep */
|
|
for _, v := range urlMap.PathMatchers {
|
|
/* If it's in the old state, we have ownership over the host rule */
|
|
_, okOld := _oldPathMatchersMap[v.Name]
|
|
vNew, okNew := _newPathMatchersMap[v.Name]
|
|
|
|
/* Drop deleted entries */
|
|
if okOld && !okNew {
|
|
continue
|
|
}
|
|
|
|
/* Don't change entries that don't belong to us */
|
|
if !okNew {
|
|
newPathMatchers = append(newPathMatchers, v)
|
|
} else {
|
|
newPathMatchers = append(newPathMatchers, createPathMatcher(vNew))
|
|
|
|
delete(_newPathMatchersMap, v.Name)
|
|
}
|
|
}
|
|
|
|
/* Record brand new host rules */
|
|
for _, v := range _newPathMatchersMap {
|
|
newPathMatchers = append(newPathMatchers, createPathMatcher(v))
|
|
}
|
|
|
|
urlMap.PathMatchers = newPathMatchers
|
|
}
|
|
|
|
if d.HasChange("test") {
|
|
_oldTests, _newTests := d.GetChange("test")
|
|
_oldTestsMap := make(map[string]interface{})
|
|
_newTestsMap := make(map[string]interface{})
|
|
|
|
for _, v := range _oldTests.([]interface{}) {
|
|
_test := v.(map[string]interface{})
|
|
ident := fmt.Sprintf("%s/%s", _test["host"].(string), _test["path"].(string))
|
|
_oldTestsMap[ident] = v
|
|
}
|
|
|
|
for _, v := range _newTests.([]interface{}) {
|
|
_test := v.(map[string]interface{})
|
|
ident := fmt.Sprintf("%s/%s", _test["host"].(string), _test["path"].(string))
|
|
_newTestsMap[ident] = v
|
|
}
|
|
|
|
newTests := make([]*compute.UrlMapTest, 0)
|
|
/* Decide which path matchers to keep */
|
|
for _, v := range urlMap.Tests {
|
|
ident := fmt.Sprintf("%s/%s", v.Host, v.Path)
|
|
/* If it's in the old state, we have ownership over the host rule */
|
|
_, okOld := _oldTestsMap[ident]
|
|
vNew, okNew := _newTestsMap[ident]
|
|
|
|
/* Drop deleted entries */
|
|
if okOld && !okNew {
|
|
continue
|
|
}
|
|
|
|
/* Don't change entries that don't belong to us */
|
|
if !okNew {
|
|
newTests = append(newTests, v)
|
|
} else {
|
|
newTests = append(newTests, createUrlMapTest(vNew))
|
|
|
|
delete(_newTestsMap, ident)
|
|
}
|
|
}
|
|
|
|
/* Record brand new host rules */
|
|
for _, v := range _newTestsMap {
|
|
newTests = append(newTests, createUrlMapTest(v))
|
|
}
|
|
|
|
urlMap.Tests = newTests
|
|
}
|
|
op, err := config.clientCompute.UrlMaps.Update(project, urlMap.Name, urlMap).Do()
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error, failed to update Url Map %s: %s", name, err)
|
|
}
|
|
|
|
err = computeOperationWaitGlobal(config, op, project, "Update Url Map")
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error, failed waitng to update Url Map %s: %s", name, err)
|
|
}
|
|
|
|
return resourceComputeUrlMapRead(d, meta)
|
|
}
|
|
|
|
func resourceComputeUrlMapDelete(d *schema.ResourceData, meta interface{}) error {
|
|
config := meta.(*Config)
|
|
|
|
project, err := getProject(d, config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
name := d.Get("name").(string)
|
|
|
|
op, err := config.clientCompute.UrlMaps.Delete(project, name).Do()
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error, failed to delete Url Map %s: %s", name, err)
|
|
}
|
|
|
|
err = computeOperationWaitGlobal(config, op, project, "Delete Url Map")
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error, failed waitng to delete Url Map %s: %s", name, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func validateHostRules(v interface{}, k string) (ws []string, es []error) {
|
|
pathMatchers := make(map[string]bool)
|
|
hostRules := v.([]interface{})
|
|
for _, hri := range hostRules {
|
|
hr := hri.(map[string]interface{})
|
|
pm := hr["path_matcher"].(string)
|
|
if pathMatchers[pm] {
|
|
es = append(es, fmt.Errorf("Multiple host_rule entries with the same path_matcher are not allowed. Please collapse all hosts with the same path_matcher into one host_rule"))
|
|
return
|
|
}
|
|
pathMatchers[pm] = true
|
|
}
|
|
return
|
|
}
|