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/environment | |
First public commit
Diffstat (limited to 'internal/environment')
| -rw-r--r-- | internal/environment/environment.go | 173 | ||||
| -rw-r--r-- | internal/environment/environment_test.go | 61 | ||||
| -rw-r--r-- | internal/environment/flags.go | 57 | 
3 files changed, 291 insertions, 0 deletions
| diff --git a/internal/environment/environment.go b/internal/environment/environment.go new file mode 100644 index 0000000..eac0430 --- /dev/null +++ b/internal/environment/environment.go @@ -0,0 +1,173 @@ +// 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 environment + +import ( +	"fmt" +	"html/template" +	"io/ioutil" +	"net" +	"os" +	"path" +	"path/filepath" +	"regexp" +	"sync" + +	"github.com/thousandeyes/shoelaces/internal/event" +	"github.com/thousandeyes/shoelaces/internal/log" +	"github.com/thousandeyes/shoelaces/internal/mappings" +	"github.com/thousandeyes/shoelaces/internal/server" +	"github.com/thousandeyes/shoelaces/internal/templates" +) + +// Environment struct holds the shoelaces instance global data. +type Environment struct { +	ConfigFile      string +	BaseURL         string +	HostnameMaps    []mappings.HostnameMap +	NetworkMaps     []mappings.NetworkMap +	ServerStates    *server.States +	EventLog        *event.Log +	ParamsBlacklist []string +	Templates       *templates.ShoelacesTemplates // Dynamic slc templates +	StaticTemplates *template.Template            // Static Templates +	Environments    []string                      // Valid config environments +	Logger          log.Logger + +	Port              int +	Domain            string +	DataDir           string +	StaticDir         string +	EnvDir            string +	TemplateExtension string +	MappingsFile      string +	Debug             bool +} + +// New returns an initialized environment structure +func New() *Environment { +	env := defaultEnvironment() +	env.setFlags() +	env.validateFlags() + +	if env.Debug { +		env.Logger = log.AllowDebug(env.Logger) +	} + +	env.BaseURL = fmt.Sprintf("%s:%d", env.Domain, env.Port) +	env.Environments = env.initEnvOverrides() + +	env.EventLog = &event.Log{} + +	env.Logger.Info("component", "environment", "msg", "Override found", "environment", env.Environments) + +	mappingsPath := path.Join(env.DataDir, env.MappingsFile) +	if err := env.initMappings(mappingsPath); err != nil { +		panic(err) +	} + +	env.initStaticTemplates() +	env.Templates.ParseTemplates(env.Logger, env.DataDir, env.EnvDir, env.Environments, env.TemplateExtension) +	server.StartStateCleaner(env.Logger, env.ServerStates) + +	return env +} + +func defaultEnvironment() *Environment { +	env := &Environment{} +	env.NetworkMaps = make([]mappings.NetworkMap, 0) +	env.HostnameMaps = make([]mappings.HostnameMap, 0) +	env.ServerStates = &server.States{sync.RWMutex{}, make(map[string]*server.State)} +	env.ParamsBlacklist = []string{"baseURL"} +	env.Templates = templates.New() +	env.Environments = make([]string, 0) +	env.Logger = log.MakeLogger(os.Stdout) + +	return env +} + +func (env *Environment) initStaticTemplates() { +	staticTemplates := []string{ +		path.Join(env.StaticDir, "templates/html/header.html"), +		path.Join(env.StaticDir, "templates/html/index.html"), +		path.Join(env.StaticDir, "templates/html/events.html"), +		path.Join(env.StaticDir, "templates/html/mappings.html"), +		path.Join(env.StaticDir, "templates/html/footer.html"), +	} + +	fmt.Println(env.StaticDir) + +	for _, t := range staticTemplates { +		if _, err := os.Stat(t); err != nil { +			env.Logger.Error("component", "environment", "msg", "Template does not exists!", "environment", t) +			os.Exit(1) +		} +	} + +	env.StaticTemplates = template.Must(template.ParseFiles(staticTemplates...)) +} + +func (env *Environment) initEnvOverrides() []string { +	var environments = make([]string, 0) +	envPath := filepath.Join(env.DataDir, env.EnvDir) +	files, err := ioutil.ReadDir(envPath) +	if err == nil { +		for _, f := range files { +			if f.IsDir() { +				environments = append(environments, f.Name()) +			} +		} +	} +	return environments +} + +func (env *Environment) initMappings(mappingsPath string) error { +	configMappings := mappings.ParseYamlMappings(env.Logger, mappingsPath) + +	for _, configNetMap := range configMappings.NetworkMaps { +		_, ipnet, err := net.ParseCIDR(configNetMap.Network) +		if err != nil { +			return err +		} + +		netMap := mappings.NetworkMap{Network: ipnet, Script: initScript(configNetMap.Script)} +		env.NetworkMaps = append(env.NetworkMaps, netMap) +	} + +	for _, configHostMap := range configMappings.HostnameMaps { +		regex, err := regexp.Compile(configHostMap.Hostname) +		if err != nil { +			return err +		} + +		hostMap := mappings.HostnameMap{Hostname: regex, Script: initScript(configHostMap.Script)} +		env.HostnameMaps = append(env.HostnameMaps, hostMap) +	} + +	return nil +} + +func initScript(configScript mappings.YamlScript) *mappings.Script { +	mappingScript := &mappings.Script{ +		Name:        configScript.Name, +		Environment: configScript.Environment, +		Params:      make(map[string]interface{}), +	} +	for key := range configScript.Params { +		mappingScript.Params[key] = configScript.Params[key] +	} + +	return mappingScript +} diff --git a/internal/environment/environment_test.go b/internal/environment/environment_test.go new file mode 100644 index 0000000..8ffe88d --- /dev/null +++ b/internal/environment/environment_test.go @@ -0,0 +1,61 @@ +// 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 environment + +import ( +	"testing" + +	"github.com/thousandeyes/shoelaces/internal/mappings" +) + +func TestDefaultEnvironment(t *testing.T) { +	env := defaultEnvironment() +	if env.BaseURL != "" { +		t.Error("BaseURL should be empty string if instantiated directly.") +	} +	if len(env.HostnameMaps) != 0 { +		t.Error("Hostname mappings should be empty") +	} +	if len(env.NetworkMaps) != 0 { +		t.Error("Network mappings should be empty") +	} +	if len(env.ParamsBlacklist) != 1 && +		env.ParamsBlacklist[0] != "baseURL" { +		t.Error("ParamsBlacklist should have only baseURL") +	} +} + +func TestInitScript(t *testing.T) { +	params := make(map[string]string) +	params["one"] = "one_value" +	configScript := mappings.YamlScript{Name: "testscript", Params: params} +	mappingScript := initScript(configScript) +	if mappingScript.Name != "testscript" { +		t.Errorf("Expected: %s\nGot: %s\n", "testscript", mappingScript.Name) +	} +	val, ok := mappingScript.Params["one"] +	if !ok { +		t.Error("Missing param") +	} else { +		v, ok := val.(string) +		if !ok { +			t.Error("Bad value type") +		} else { +			if v != "one_value" { +				t.Error("Bad value") +			} +		} +	} +} diff --git a/internal/environment/flags.go b/internal/environment/flags.go new file mode 100644 index 0000000..8250690 --- /dev/null +++ b/internal/environment/flags.go @@ -0,0 +1,57 @@ +// 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 environment + +import ( +	"fmt" +	"os" + +	"github.com/namsral/flag" +) + +func (env *Environment) setFlags() { +	flag.StringVar(&env.ConfigFile, "config", "", "My config file") +	flag.IntVar(&env.Port, "port", 8080, "The port where I'm going to listen") +	flag.StringVar(&env.Domain, "domain", "localhost", "The address where I'm going to listen") +	flag.StringVar(&env.DataDir, "data-dir", "", "Directory with mappings, configs, templates, etc.") +	flag.StringVar(&env.StaticDir, "static-dir", "web", "A custom web directory with static files") +	flag.StringVar(&env.EnvDir, "env-dir", "env_overrides", "Directory with overrides") +	flag.StringVar(&env.TemplateExtension, "template-extension", ".slc", "Shoelaces template extension") +	flag.StringVar(&env.MappingsFile, "mappings-file", "mappings.yaml", "My mappings YAML file") +	flag.BoolVar(&env.Debug, "debug", false, "Debug mode") + +	flag.Parse() +} + +func (env *Environment) validateFlags() { +	error := false + +	if env.DataDir == "" { +		fmt.Println("[*] You must specify the data-dir parameter") +		error = true +	} + +	if env.StaticDir == "" { +		fmt.Println("[*] You must specify the data-dir parameter") +		error = true +	} + +	if error { +		fmt.Println("\nAvailable parameters:") +		flag.PrintDefaults() +		fmt.Println("\nParameters can be specified as environment variables, arguments or in a config file.") +		os.Exit(1) +	} +} | 
