diff options
| author | Raúl Benencia <raul@thousandeyes.com> | 2018-04-13 16:30:31 -0700 | 
|---|---|---|
| committer | Raúl Benencia <raul@thousandeyes.com> | 2018-05-11 15:02:34 -0700 | 
| commit | 77c172b823b64ebface655681ab0749b9d2f7081 (patch) | |
| tree | 09c13e626eb95ae1d33e76ed683172eab1ab6c96 /internal/mappings | |
First public commit
Diffstat (limited to 'internal/mappings')
| -rw-r--r-- | internal/mappings/mappings.go | 80 | ||||
| -rw-r--r-- | internal/mappings/mappings_test.go | 100 | ||||
| -rw-r--r-- | internal/mappings/parse.go | 78 | 
3 files changed, 258 insertions, 0 deletions
| diff --git a/internal/mappings/mappings.go b/internal/mappings/mappings.go new file mode 100644 index 0000000..fba7201 --- /dev/null +++ b/internal/mappings/mappings.go @@ -0,0 +1,80 @@ +// Copyright 2018 ThousandEyes Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mappings + +import ( +	"net" +	"regexp" +	"strings" +) + +// Script holds information related to a booting script. +type Script struct { +	Name        string +	Environment string +	Params      map[string]interface{} +} + +// NetworkMap struct contains an association between a CIDR network and a +// Script. +type NetworkMap struct { +	Network *net.IPNet +	Script  *Script +} + +// HostnameMap struct contains an association between a hostname regular +// expression and a Script. +type HostnameMap struct { +	Hostname *regexp.Regexp +	Script   *Script +} + +// FindScriptForHostname receives a HostnameMap and a string (that can be a +// regular expression), and tries to find a match in that map. If it finds +// a match, it returns the associated script. +func FindScriptForHostname(maps []HostnameMap, hostname string) (script *Script, ok bool) { +	for _, m := range maps { +		if m.Hostname.MatchString(hostname) { +			return m.Script, true +		} +	} +	return nil, false +} + +// FindScriptForNetwork receives a NetworkMap and an IP and tries to see if +// that IP belongs to any of the configured networks. If it finds a match, +// it returns the associated script. +func FindScriptForNetwork(maps []NetworkMap, ip string) (script *Script, ok bool) { +	for _, m := range maps { +		if m.Network.Contains(net.ParseIP(ip)) { +			return m.Script, true +		} +	} +	return nil, false +} + +func (s Script) String() string { +	var result = s.Name + " : { " +	elems := []string{} +	if s.Environment != "" { +		elems = append(elems, "environment: "+s.Environment) +	} +	for key, value := range s.Params { +		elems = append(elems, key+": "+value.(string)) +	} +	result += strings.Join(elems, ", ") + " }" + +	return result +} diff --git a/internal/mappings/mappings_test.go b/internal/mappings/mappings_test.go new file mode 100644 index 0000000..ed45114 --- /dev/null +++ b/internal/mappings/mappings_test.go @@ -0,0 +1,100 @@ +// Copyright 2018 ThousandEyes Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mappings + +import ( +	"net" +	"regexp" +	"testing" +) + +var ( +	mockScriptParams1 = map[string]interface{}{ +		"param11": "param1_value1", +		"param21": "param2_value1", +	} +	mockScriptParams2 = map[string]interface{}{ +		"param12": "param1_value2", +		"param22": "param2_value2", +	} +	mockScript1 = Script{Name: "mock_script1", Params: mockScriptParams1} +	mockScript2 = Script{Name: "mock_script2", Params: mockScriptParams2} + +	mockRegex1, _ = regexp.Compile("mock_host1") +	mockRegex2, _ = regexp.Compile("mock_host2") + +	mockHostNameMap1 = HostnameMap{ +		Hostname: mockRegex1, +		Script:   &mockScript1, +	} + +	mockHostNameMap2 = HostnameMap{ +		Hostname: mockRegex2, +		Script:   &mockScript2, +	} + +	_, mockNetwork1, _ = net.ParseCIDR("10.0.0.0/8") +	_, mockNetwork2, _ = net.ParseCIDR("192.168.0.0/16") + +	mockNetworkMap1 = NetworkMap{ +		Network: mockNetwork1, +		Script:  &mockScript1, +	} +	mockNetworkMap2 = NetworkMap{ +		Network: mockNetwork2, +		Script:  &mockScript2, +	} +) + +func TestScript(t *testing.T) { +	expected1 := "mock_script1 : { param11: param1_value1, param21: param2_value1 }" +	expected2 := "mock_script1 : { param21: param2_value1, param11: param1_value1 }" +	mockScriptString := mockScript1.String() +	if mockScriptString != expected1 && mockScriptString != expected2 { +		t.Errorf("Expected: %s or %s\nGot: %s\n", expected1, expected2, mockScriptString) +	} +} + +func TestFindScriptForHostname(t *testing.T) { +	maps := []HostnameMap{mockHostNameMap1, mockHostNameMap2} +	script, success := FindScriptForHostname(maps, "mock_host1") +	if !(script.Name == "mock_script1" && success) { +		t.Error("Hostname should have matched") +	} +	script, success = FindScriptForHostname(maps, "mock_host2") +	if !(script.Name == "mock_script2" && success) { +		t.Error("Hostname should have matched") +	} +	script, success = FindScriptForHostname(maps, "mock_host_bad") +	if !(script == nil && !success) { +		t.Error("Hostname should have not matched") +	} +} + +func TestScriptForNetwork(t *testing.T) { +	maps := []NetworkMap{mockNetworkMap1, mockNetworkMap2} +	script, success := FindScriptForNetwork(maps, "10.0.0.1") +	if !(script.Name == "mock_script1" && success) { +		t.Error("IP should have matched the network map") +	} +	script, success = FindScriptForNetwork(maps, "192.168.0.1") +	if !(script.Name == "mock_script2" && success) { +		t.Error("IP should have matched the network map") +	} +	script, success = FindScriptForNetwork(maps, "8.8.8.8") +	if !(script == nil && !success) { +		t.Error("IP shouildn't have matched the network map") +	} +} diff --git a/internal/mappings/parse.go b/internal/mappings/parse.go new file mode 100644 index 0000000..64de5bb --- /dev/null +++ b/internal/mappings/parse.go @@ -0,0 +1,78 @@ +// Copyright 2018 ThousandEyes Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mappings + +import ( +	"io/ioutil" +	"os" + +	"gopkg.in/yaml.v2" + +	"github.com/thousandeyes/shoelaces/internal/log" +) + +// Mappings struct contains YamlNetworkMaps and YamlHostnameMaps. +type Mappings struct { +	NetworkMaps  []YamlNetworkMap  `yaml:"networkMaps"` +	HostnameMaps []YamlHostnameMap `yaml:"hostnameMaps"` +} + +// YamlNetworkMap struct contains an association between a CIDR network and a +// Script. It's different than mapping.NetworkMap in the sense that this +// struct can be used to parse the JSON mapping file. +type YamlNetworkMap struct { +	Network string +	Script  YamlScript +} + +// YamlHostnameMap struct contains an association between a hostname regular +// expression and a Script. It's different than mapping.HostnameMap in the +// sense that this struct can be used to parse the JSON mapping file. +type YamlHostnameMap struct { +	Hostname string +	Script   YamlScript +} + +// YamlScript holds information regarding a script. Its name, its environment +// and its parameters. +type YamlScript struct { +	Name        string +	Environment string +	Params      map[string]string +} + +// ParseYamlMappings parses the mappings yaml file into a Mappings struct. +func ParseYamlMappings(logger log.Logger, mappingsFile string) *Mappings { +	var mappings Mappings + +	logger.Info("component", "config", "msg", "Reading mappings", "source", mappingsFile) +	yamlFile, err := ioutil.ReadFile(mappingsFile) + +	if err != nil { +		logger.Error(err) +		os.Exit(1) +	} + +	mappings.NetworkMaps = make([]YamlNetworkMap, 0) +	mappings.HostnameMaps = make([]YamlHostnameMap, 0) + +	err = yaml.Unmarshal(yamlFile, &mappings) +	if err != nil { +		logger.Error(err) +		os.Exit(1) +	} + +	return &mappings +} | 
