| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 config provides tools to load and validate configuration data for |
| // Traffic Ops API tests. |
| package config |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "io/ioutil" |
| "reflect" |
| "strings" |
| |
| log "github.com/apache/trafficcontrol/lib/go-log" |
| "github.com/kelseyhightower/envconfig" |
| ) |
| |
| // Config reflects the structure of the test-to-api.conf file |
| type Config struct { |
| TrafficOps TrafficOps `json:"trafficOps"` |
| TrafficOpsDB TrafficOpsDB `json:"trafficOpsDB"` |
| Default Default `json:"default"` |
| UseIMS bool `json:"use_ims"` |
| // Sets whether or not to perform tests that must proxy to Perl |
| NoPerl bool `json:"noPerl"` |
| // Sets whether or not to perform tests that involve ISO generation |
| NoISO bool `json:"noISO"` |
| } |
| |
| // TrafficOps - config section |
| type TrafficOps struct { |
| // URL - The point to the Traffic Ops instance being tested |
| URL string `json:"URL" envconfig:"TO_URL"` |
| |
| // UserPassword - The Traffic Ops test user password hitting the API |
| UserPassword string `json:"password" envconfig:"TO_USER_PASSWORD"` |
| |
| // User - The Traffic Ops Users |
| Users Users `json:"users"` |
| |
| // Insecure - ignores insecure ssls certs that were self-generated |
| Insecure bool `json:"sslInsecure" envconfig:"SSL_INSECURE"` |
| } |
| |
| // Users "users" section of the test-to-api.conf file |
| type Users struct { |
| |
| // DisallowedUser - The Traffic Ops Disallowed user |
| Disallowed string `json:"disallowed" envconfig:"TO_USER_DISALLOWED"` |
| |
| // ReadOnly - The Traffic Ops Read Only user |
| ReadOnly string `json:"readOnly" envconfig:"TO_USER_READ_ONLY"` |
| |
| // Operations - The Traffic Ops Operations user |
| Operations string `json:"operations" envconfig:"TO_USER_OPERATIONS"` |
| |
| // AdminUser - The Traffic Ops Admin user |
| Admin string `json:"admin" envconfig:"TO_USER_ADMIN"` |
| |
| // PortalUser - The Traffic Ops Portal user |
| Portal string `json:"portal" envconfig:"TO_USER_PORTAL"` |
| |
| // FederationUser - The Traffic Ops Federation user |
| Federation string `json:"federation" envconfig:"TO_USER_FEDERATION"` |
| |
| // Extension - The Traffic Ops Extension user |
| Extension string `json:"extension" envconfig:"TO_USER_EXTENSION"` |
| } |
| |
| // TrafficOpsDB - config section |
| type TrafficOpsDB struct { |
| // Name - Traffic Ops Database name where the test data will be setup |
| Name string `json:"dbname" envconfig:"TODB_NAME"` |
| |
| // Hostname - Traffic Ops Database hostname where Postgres is running |
| Hostname string `json:"hostname" envconfig:"TODB_HOSTNAME"` |
| |
| // User - database user that Traffic Ops is using to point to the 'to_test' database |
| User string `json:"user" envconfig:"TODB_USER"` |
| |
| // Password - database password for the User above |
| Password string `json:"password" envconfig:"TODB_PASSWORD"` |
| |
| // Port - Postgres port running that has the to_test schema |
| Port string `json:"port" envconfig:"TODB_PORT"` |
| |
| // DBType - will be 'Pg' by default but tells the Golang database driver |
| // the database type |
| DBType string `json:"type" envconfig:"TODB_TYPE"` |
| |
| // SSL - Flag that tells the database driver that the Postgres instances has TLS enabled |
| SSL bool `json:"ssl" envconfig:"TODB_SSL"` |
| |
| // Description - database description |
| Description string `json:"description" envconfig:"TODB_DESCRIPTION"` |
| } |
| |
| // Default - config section |
| type Default struct { |
| Session Session `json:"session"` |
| Log Locations `json:"logLocations"` |
| IncludeSystemTests bool `json:"includeSystemTests"` |
| } |
| |
| // Session - config section |
| type Session struct { |
| TimeoutInSecs int `json:"timeoutInSecs" envconfig:"SESSION_TIMEOUT_IN_SECS"` |
| } |
| |
| // Locations - reflects the structure of the database.conf file |
| type Locations struct { |
| Debug string `json:"debug"` |
| Event string `json:"event"` |
| Error string `json:"error"` |
| Info string `json:"info"` |
| Warning string `json:"warning"` |
| } |
| |
| // LoadConfig - reads the config file into the Config struct |
| func LoadConfig(confPath string) (Config, error) { |
| var cfg Config |
| |
| confBytes, err := ioutil.ReadFile(confPath) |
| if err != nil { |
| return cfg, fmt.Errorf("failed to read CDN configuration: %v", err) |
| } |
| |
| err = json.Unmarshal(confBytes, &cfg) |
| if err != nil { |
| return cfg, fmt.Errorf("failed to parse configuration from '%s': %v", confPath, err) |
| } |
| |
| if err := validate(confPath, cfg); err != nil { |
| return cfg, fmt.Errorf("failed to validate configuration:\n%v", err) |
| } |
| |
| if err := envconfig.Process("traffic-ops-client-tests", &cfg); err != nil { |
| return cfg, fmt.Errorf("failed to parse configuration from environment: %v", err) |
| } |
| |
| return cfg, nil |
| } |
| |
| type multiError []error |
| |
| func (me multiError) Error() string { |
| var sb strings.Builder |
| for _, e := range me { |
| fmt.Fprintln(&sb, e) |
| } |
| return sb.String() |
| } |
| |
| // validate all required fields in the config. |
| func validate(confPath string, config Config) error { |
| var errs multiError |
| |
| var f string |
| f = "TrafficOps" |
| toTag, ok := getStructTag(config, f) |
| if !ok { |
| errs = append(errs, fmt.Errorf("'%s' must be configured in %s", toTag, confPath)) |
| } |
| |
| if config.TrafficOps.URL == "" { |
| f = "URL" |
| tag, ok := getStructTag(config.TrafficOps, f) |
| if !ok { |
| errs = append(errs, fmt.Errorf("cannot lookup structTag: %s", f)) |
| } |
| errs = append(errs, fmt.Errorf("'%s.%s' must be configured in %s", toTag, tag, confPath)) |
| } |
| |
| if config.TrafficOps.Users.Disallowed == "" { |
| f = "Disallowed" |
| tag, ok := getStructTag(config.TrafficOps.Users, f) |
| if !ok { |
| errs = append(errs, fmt.Errorf("cannot lookup structTag: %s", f)) |
| } |
| errs = append(errs, fmt.Errorf("'%s.%s' must be configured in %s", toTag, tag, confPath)) |
| } |
| |
| if config.TrafficOps.Users.ReadOnly == "" { |
| f = "ReadOnly" |
| tag, ok := getStructTag(config.TrafficOps.Users, f) |
| if !ok { |
| errs = append(errs, fmt.Errorf("cannot lookup structTag: %s", f)) |
| } |
| errs = append(errs, fmt.Errorf("'%s.%s' must be configured in %s", toTag, tag, confPath)) |
| } |
| |
| if config.TrafficOps.Users.Operations == "" { |
| f = "Operations" |
| tag, ok := getStructTag(config.TrafficOps.Users, f) |
| if !ok { |
| errs = append(errs, fmt.Errorf("cannot lookup structTag: %s", f)) |
| } |
| errs = append(errs, fmt.Errorf("'%s.%s' must be configured in %s", toTag, tag, confPath)) |
| } |
| |
| if config.TrafficOps.Users.Admin == "" { |
| f = "Admin" |
| tag, ok := getStructTag(config.TrafficOps.Users, f) |
| if !ok { |
| errs = append(errs, fmt.Errorf("cannot lookup structTag: %s", f)) |
| } |
| errs = append(errs, fmt.Errorf("'%s.%s' must be configured in %s", toTag, tag, confPath)) |
| } |
| |
| if config.TrafficOps.Users.Portal == "" { |
| f = "Portal" |
| tag, ok := getStructTag(config.TrafficOps.Users, f) |
| if !ok { |
| errs = append(errs, fmt.Errorf("cannot lookup structTag: %s", f)) |
| } |
| errs = append(errs, fmt.Errorf("'%s.%s' must be configured in %s", toTag, tag, confPath)) |
| } |
| |
| if config.TrafficOps.Users.Federation == "" { |
| f = "Federation" |
| tag, ok := getStructTag(config.TrafficOps.Users, f) |
| if !ok { |
| errs = append(errs, fmt.Errorf("cannot lookup structTag: %s", f)) |
| } |
| errs = append(errs, fmt.Errorf("'%s.%s' must be configured in %s", toTag, tag, confPath)) |
| } |
| |
| if len(errs) > 0 { |
| return errs |
| } |
| return nil |
| } |
| |
| func getStructTag(thing interface{}, fieldName string) (string, bool) { |
| var tag string |
| var ok bool |
| t := reflect.TypeOf(thing) |
| if t != nil { |
| if f, ok := t.FieldByName(fieldName); ok { |
| tag = f.Tag.Get("json") |
| return tag, ok |
| } |
| } |
| return tag, ok |
| } |
| |
| // ErrorLog - critical messages |
| func (c Config) ErrorLog() log.LogLocation { |
| return log.LogLocation(c.Default.Log.Error) |
| } |
| |
| // WarningLog - warning messages |
| func (c Config) WarningLog() log.LogLocation { |
| return log.LogLocation(c.Default.Log.Warning) |
| } |
| |
| // InfoLog - information messages |
| func (c Config) InfoLog() log.LogLocation { |
| return log.LogLocation(c.Default.Log.Info) |
| } |
| |
| // DebugLog - troubleshooting messages |
| func (c Config) DebugLog() log.LogLocation { |
| return log.LogLocation(c.Default.Log.Debug) |
| } |
| |
| // EventLog - access.log high level transactions |
| func (c Config) EventLog() log.LogLocation { |
| return log.LogLocation(c.Default.Log.Event) |
| } |