Add TO Golang old perl config reading

Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/8b0ac5f9
Tree: 
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/8b0ac5f9
Diff: 
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/8b0ac5f9

Branch: refs/heads/master
Commit: 8b0ac5f9e00d188e535b6b35a3f6fdb7298c59da
Parents: 70b7e5c
Author: Robert Butts <robert.o.bu...@gmail.com>
Authored: Sun Jul 23 14:53:08 2017 -0600
Committer: Dewayne Richardson <dewr...@apache.org>
Committed: Thu Aug 10 09:46:03 2017 -0600

----------------------------------------------------------------------
 traffic_ops/app/lib/TrafficOps.pm               |   2 +-
 traffic_ops/build/traffic_ops.spec              |  13 +-
 traffic_ops/traffic_ops_golang/perlconfig.go    | 288 +++++++++++++++++++
 .../traffic_ops_golang/perlconfig_test.go       | 166 +++++++++++
 .../traffic_ops_golang/traffic_ops_golang.go    |  21 +-
 5 files changed, 483 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/8b0ac5f9/traffic_ops/app/lib/TrafficOps.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/TrafficOps.pm 
b/traffic_ops/app/lib/TrafficOps.pm
index 43b5bdf..3695031 100644
--- a/traffic_ops/app/lib/TrafficOps.pm
+++ b/traffic_ops/app/lib/TrafficOps.pm
@@ -349,7 +349,7 @@ sub setup_mojo_plugins {
 
        $self->plugin(
                AccessLog => {
-                       log    => "$logging_root_dir/access.log",
+                       log    => "$logging_root_dir/perl_access.log",
                        uname_helper => 'set_username',
                        format => '%h %l %u %t "%r" %>s %b %D "%{User-Agent}i"'
                }

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/8b0ac5f9/traffic_ops/build/traffic_ops.spec
----------------------------------------------------------------------
diff --git a/traffic_ops/build/traffic_ops.spec 
b/traffic_ops/build/traffic_ops.spec
index 66d2fd9..8efa676 100644
--- a/traffic_ops/build/traffic_ops.spec
+++ b/traffic_ops/build/traffic_ops.spec
@@ -60,14 +60,23 @@ Built: %(date) by %{getenv: USER}
     mkdir -p src pkg bin || { echo "Could not create directories in $(pwd): 
$!"; exit 1; }
 
     # build tocookie (dependencies within traffic_control will fail to `go 
get` unless prebuilt)
-    
godir=src/github.com/apache/incubator-trafficcontrol/traffic_ops/experimental/tocookie
+    godir=src/github.com/apache/incubator-trafficcontrol/traffic_ops/tocookie
     ( mkdir -p "$godir" && \
       cd "$godir" && \
-      cp -r "$TC_DIR"/traffic_ops/experimental/tocookie/* . && \
+      cp -r "$TC_DIR"/traffic_ops/tocookie/* . && \
       echo "go getting tocookie at $(pwd)" && \
       go get -v \
     ) || { echo "Could not build go tocookie at $(pwd): $!"; exit 1; }
 
+    # build log (dependencies within traffic_control will fail to `go get` 
unless prebuilt)
+    
godir=src/github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/common/log
+    ( mkdir -p "$godir" && \
+      cd "$godir" && \
+      cp -r "$TC_DIR"/traffic_monitor_golang/common/log/* . && \
+      echo "go getting log at $(pwd)" && \
+      go get -v \
+    ) || { echo "Could not build go log at $(pwd): $!"; exit 1; }
+
     # build traffic_ops_golang binary
     
godir=src/github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang
     oldpwd=$(pwd)

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/8b0ac5f9/traffic_ops/traffic_ops_golang/perlconfig.go
----------------------------------------------------------------------
diff --git a/traffic_ops/traffic_ops_golang/perlconfig.go 
b/traffic_ops/traffic_ops_golang/perlconfig.go
new file mode 100644
index 0000000..c7abf64
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/perlconfig.go
@@ -0,0 +1,288 @@
+package main
+
+/*
+ * 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.
+ */
+
+import (
+       "encoding/json"
+       "fmt"
+       "io/ioutil"
+       "net/url"
+       "regexp"
+       "strconv"
+       "strings"
+
+       
"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/common/log"
+)
+
+const OldAccessLogPath = "/var/log/traffic_ops/access.log"
+const NewLogPath = "/var/log/traffic_ops/traffic_ops_golang.log"
+
+func GetPerlConfigs(cdnConfPath string, dbConfPath string) (Config, error) {
+       configBytes, err := ioutil.ReadFile(cdnConfPath)
+       if err != nil {
+               return Config{}, fmt.Errorf("reading CDN conf '%v': %v", 
cdnConfPath, err)
+       }
+       dbConfBytes, err := ioutil.ReadFile(dbConfPath)
+       if err != nil {
+               return Config{}, fmt.Errorf("reading db conf '%v': %v", 
dbConfPath, err)
+       }
+       return getPerlConfigsFromStrs(string(configBytes), string(dbConfBytes))
+}
+
+func getPerlConfigsFromStrs(cdnConfBytes string, dbConfBytes string) (Config, 
error) {
+       cfg, err := getCDNConf(cdnConfBytes)
+       if err != nil {
+               return Config{}, fmt.Errorf("parsing CDN conf '%v': %v", 
cdnConfBytes, err)
+       }
+
+       dbconf, err := getDbConf(string(dbConfBytes))
+       if err != nil {
+               return Config{}, fmt.Errorf("parsing db conf '%v': %v", 
dbConfBytes, err)
+       }
+       cfg.DBUser = dbconf.User
+       cfg.DBPass = dbconf.Password
+       cfg.DBServer = dbconf.Hostname
+       cfg.DBDB = dbconf.DBName
+       cfg.DBSSL = false // TODO fix
+       if dbconf.Port != "" {
+               cfg.DBServer += ":" + dbconf.Port
+       }
+
+       cfg.LogLocationInfo = OldAccessLogPath
+       cfg.LogLocationError = NewLogPath
+       cfg.LogLocationWarning = NewLogPath
+       cfg.LogLocationEvent = NewLogPath
+       cfg.LogLocationDebug = log.LogLocationNull
+
+       return cfg, nil
+}
+
+func getCDNConf(s string) (Config, error) {
+       cfg := Config{}
+       obj, err := ParsePerlObj(s)
+       if err != nil {
+               return Config{}, fmt.Errorf("parsing Perl object: %v", err)
+       }
+
+       if cfg.HTTPPort, err = getPort(obj); err != nil {
+               return Config{}, err
+       }
+
+       if cfg.TOSecret, err = getSecret(obj); err != nil {
+               return Config{}, err
+       }
+
+       oldPort, err := getOldPort(obj)
+       if err != nil {
+               return Config{}, err
+       }
+       cfg.TOURLStr = "https://127.0.0.1:"; + oldPort
+       if cfg.TOURL, err = url.Parse(cfg.TOURLStr); err != nil {
+               return Config{}, fmt.Errorf("Invalid Traffic Ops URL '%v': 
err", cfg.TOURL, err)
+       }
+
+       cfg.CertPath, err = getConfigCert(obj)
+       if err != nil {
+               return Config{}, err
+       }
+
+       cfg.KeyPath, err = getConfigKey(obj)
+       if err != nil {
+               return Config{}, err
+       }
+
+       return cfg, nil
+}
+
+func getPort(obj map[string]interface{}) (string, error) {
+       portStrI, ok := obj["traffic_ops_golang_port"]
+       if !ok {
+               return "", fmt.Errorf("missing traffic_ops_golang_port key")
+       }
+       portStr, ok := portStrI.(string)
+       if !ok {
+               return "", fmt.Errorf("traffic_ops_golang_port key '%v' not a 
string", portStrI)
+       }
+
+       port, err := strconv.Atoi(portStr)
+       if err != nil || port < 0 || port > 65535 {
+               return "", fmt.Errorf("invalid port '%s'", portStr)
+       }
+       return strconv.Itoa(port), nil
+}
+
+func getOldPort(obj map[string]interface{}) (string, error) {
+       hypnotoadI, ok := obj["hypnotoad"]
+       if !ok {
+               return "", fmt.Errorf("missing hypnotoad key")
+       }
+       hypnotoad, ok := hypnotoadI.(map[string]interface{})
+       if !ok {
+               return "", fmt.Errorf("hypnotoad key '%v' not an object", 
hypnotoadI)
+       }
+
+       listenArrI, ok := hypnotoad["listen"]
+       if !ok {
+               return "", fmt.Errorf("missing hypnotoad.listen key")
+       }
+       listenArr, ok := listenArrI.([]interface{})
+       if !ok {
+               return "", fmt.Errorf("listen key '%v' type %T not an array", 
listenArrI, listenArrI)
+       }
+       if len(listenArr) < 1 {
+               return "", fmt.Errorf("empty hypnotoad.listen key")
+       }
+       listenI := listenArr[0]
+       listen, ok := listenI.(string)
+       if !ok {
+               return "", fmt.Errorf("listen[0] key '%v' type %T not a 
string", listenI, listenI)
+       }
+
+       listenRe := regexp.MustCompile(`:(\d+)`)
+       portMatch := listenRe.FindStringSubmatch(listen)
+       if len(portMatch) < 2 {
+               return "", fmt.Errorf("failed to find port in listen '%s'", 
listen)
+       }
+       portStr := portMatch[1]
+
+       port, err := strconv.Atoi(portStr)
+       if err != nil || port < 0 || port > 65535 {
+               return "", fmt.Errorf("invalid port in listen '%s'", listen)
+       }
+       return strconv.Itoa(port), nil
+}
+
+func getConfigCert(obj map[string]interface{}) (string, error) {
+       hypnotoadI, ok := obj["hypnotoad"]
+       if !ok {
+               return "", fmt.Errorf("missing hypnotoad key")
+       }
+       hypnotoad, ok := hypnotoadI.(map[string]interface{})
+       if !ok {
+               return "", fmt.Errorf("hypnotoad key '%v' not an object", 
hypnotoadI)
+       }
+
+       listenArrI, ok := hypnotoad["listen"]
+       if !ok {
+               return "", fmt.Errorf("missing hypnotoad.listen key")
+       }
+       listenArr, ok := listenArrI.([]interface{})
+       if !ok {
+               return "", fmt.Errorf("listen key '%v' type %T not an array", 
listenArrI, listenArrI)
+       }
+       if len(listenArr) < 1 {
+               return "", fmt.Errorf("empty hypnotoad.listen key")
+       }
+       listenI := listenArr[0]
+       listen, ok := listenI.(string)
+       if !ok {
+               return "", fmt.Errorf("listen[0] key '%v' type %T not a 
string", listenI, listenI)
+       }
+
+       keyStr := "cert="
+       start := strings.Index(listen, keyStr)
+       if start < 0 {
+               return "", fmt.Errorf("failed to find key in listen '%s'", 
listen)
+       }
+       listen = listen[start+len(keyStr):]
+       end := strings.Index(listen, "&")
+       if end < 0 {
+               return listen[start:], nil
+       }
+       return listen[:end], nil
+}
+
+func getConfigKey(obj map[string]interface{}) (string, error) {
+       hypnotoadI, ok := obj["hypnotoad"]
+       if !ok {
+               return "", fmt.Errorf("missing hypnotoad key")
+       }
+       hypnotoad, ok := hypnotoadI.(map[string]interface{})
+       if !ok {
+               return "", fmt.Errorf("hypnotoad key '%v' not an object", 
hypnotoadI)
+       }
+
+       listenArrI, ok := hypnotoad["listen"]
+       if !ok {
+               return "", fmt.Errorf("missing hypnotoad.listen key")
+       }
+       listenArr, ok := listenArrI.([]interface{})
+       if !ok {
+               return "", fmt.Errorf("listen key '%v' type %T not an array", 
listenArrI, listenArrI)
+       }
+       if len(listenArr) < 1 {
+               return "", fmt.Errorf("empty hypnotoad.listen key")
+       }
+       listenI := listenArr[0]
+       listen, ok := listenI.(string)
+       if !ok {
+               return "", fmt.Errorf("listen[0] key '%v' type %T not a 
string", listenI, listenI)
+       }
+
+       keyStr := "key="
+       start := strings.Index(listen, keyStr)
+       if start < 0 {
+               return "", fmt.Errorf("failed to find key in listen '%s'", 
listen)
+       }
+       listen = listen[start+len(keyStr):]
+       end := strings.Index(listen, "&")
+       if end < 0 {
+               return listen[start:], nil
+       }
+       return listen[:end], nil
+}
+
+func getSecret(obj map[string]interface{}) (string, error) {
+       secretsI, ok := obj["secrets"]
+       if !ok {
+               return "", fmt.Errorf("missing secrets key")
+       }
+       secrets, ok := secretsI.([]interface{})
+       if !ok {
+               return "", fmt.Errorf("secrets key '%v' not an array", secretsI)
+       }
+
+       if len(secrets) < 1 {
+               return "", fmt.Errorf("empty secrets key")
+       }
+       secretI := secrets[0]
+       secret, ok := secretI.(string)
+       if !ok {
+               return "", fmt.Errorf("secret '%v' not a string", secretI)
+       }
+
+       return secret, nil
+}
+
+type DatabaseConf struct {
+       Description string `json:"description"`
+       DBName      string `json:"dbname"`
+       Hostname    string `json:"hostname"`
+       User        string `json:"user"`
+       Password    string `json:"password"`
+       Port        string `json:"port"`
+       Type        string `json:"type"`
+}
+
+func getDbConf(s string) (DatabaseConf, error) {
+       dbc := DatabaseConf{}
+       err := json.Unmarshal([]byte(s), &dbc)
+       return dbc, err
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/8b0ac5f9/traffic_ops/traffic_ops_golang/perlconfig_test.go
----------------------------------------------------------------------
diff --git a/traffic_ops/traffic_ops_golang/perlconfig_test.go 
b/traffic_ops/traffic_ops_golang/perlconfig_test.go
new file mode 100644
index 0000000..8242d5c
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/perlconfig_test.go
@@ -0,0 +1,166 @@
+package main
+
+/*
+ * 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.
+ */
+
+import (
+       "net/url"
+       "reflect"
+       "testing"
+
+       
"github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/common/log"
+)
+
+func TestGetCDNConf(t *testing.T) {
+       input := `
+{
+       hypnotoad => {
+               listen => [
+                       
'https://[::]:60443?cert=/etc/pki/tls/certs/localhost.crt&key=/etc/pki/tls/private/localhost.key&verify=0x00&ciphers=AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH:!ED'
+               ],
+               user     => 'trafops',
+               group    => 'trafops',
+               heartbeat_timeout => 20,
+               pid_file => '/var/run/traffic_ops.pid',
+               workers  => 96
+       },
+       cors => {
+               access_control_allow_origin => '*'
+       },
+       to => {
+               base_url   => 'http://localhost:3000',                    # 
this is where traffic ops app resides
+               email_from => 'no-re...@traffic-ops-domain.com'           # 
traffic ops email address
+       },
+       portal => {
+               base_url   => 'http://localhost:8080',                    # 
this is where the traffic portal resides (a javascript client that consumes the 
TO API)
+               email_from => 'no-re...@traffic-portal-domain.com'        # 
traffic portal email address
+       },
+
+       # 1st secret is used to generate new signatures. Older one kept around 
for existing signed cookies.
+               #  Remove old one(s) when ready to invalidate old cookies.
+               secrets => [ 'walrus' ],
+       geniso  => {
+               iso_root_path => '/opt/traffic_ops/app/public',          # the 
location where the iso files will be written
+       },
+       inactivity_timeout => 60,
+       traffic_ops_golang_port => '443'
+};
+`
+
+       expected := Config{
+               HTTPPort: "443",
+               TOSecret: "walrus",
+               TOURLStr: "https://127.0.0.1:60443";,
+               CertPath: "/etc/pki/tls/certs/localhost.crt",
+               KeyPath:  "/etc/pki/tls/private/localhost.key",
+       }
+       err := error(nil)
+       if expected.TOURL, err = url.Parse(expected.TOURLStr); err != nil {
+               t.Errorf("expected URL parse '%+v' err nil actual %+v", 
expected.TOURLStr, err)
+       }
+
+       cfg, err := getCDNConf(input)
+       if err != nil {
+               t.Errorf("expected nil err actual %v", err)
+       }
+
+       if !reflect.DeepEqual(cfg, expected) {
+               t.Errorf("expected %+v actual %+v", expected, cfg)
+       }
+}
+
+func TestGetPerlConfigsFromStrs(t *testing.T) {
+       cdnConfInput := `
+{
+       hypnotoad => {
+               listen => [
+                       
'https://[::]:60443?cert=/etc/pki/tls/certs/localhost.crt&key=/etc/pki/tls/private/localhost.key&verify=0x00&ciphers=AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH:!ED'
+               ],
+               user     => 'trafops',
+               group    => 'trafops',
+               heartbeat_timeout => 20,
+               pid_file => '/var/run/traffic_ops.pid',
+               workers  => 96
+       },
+       cors => {
+               access_control_allow_origin => '*'
+       },
+       to => {
+               base_url   => 'http://localhost:3000',                    # 
this is where traffic ops app resides
+               email_from => 'no-re...@traffic-ops-domain.com'           # 
traffic ops email address
+       },
+       portal => {
+               base_url   => 'http://localhost:8080',                    # 
this is where the traffic portal resides (a javascript client that consumes the 
TO API)
+               email_from => 'no-re...@traffic-portal-domain.com'        # 
traffic portal email address
+       },
+
+       # 1st secret is used to generate new signatures. Older one kept around 
for existing signed cookies.
+               #  Remove old one(s) when ready to invalidate old cookies.
+               secrets => [ 'walrus' ],
+       geniso  => {
+               iso_root_path => '/opt/traffic_ops/app/public',          # the 
location where the iso files will be written
+       },
+       inactivity_timeout => 60,
+       traffic_ops_golang_port => '443'
+};
+`
+
+       dbConfInput := `
+{
+   "password" : "thelizard",
+   "user" : "bill",
+   "type" : "Pg",
+   "hostname" : "db.to.example.net",
+   "description" : "Postgres database",
+   "port" : "5432",
+   "dbname" : "to"
+}
+`
+
+       expected := Config{
+               HTTPPort:           "443",
+               DBUser:             "bill",
+               DBPass:             "thelizard",
+               DBServer:           "db.to.example.net:5432",
+               DBDB:               "to",
+               DBSSL:              false,
+               TOSecret:           "walrus",
+               TOURLStr:           "https://127.0.0.1:60443";,
+               CertPath:           "/etc/pki/tls/certs/localhost.crt",
+               KeyPath:            "/etc/pki/tls/private/localhost.key",
+               LogLocationError:   NewLogPath,
+               LogLocationWarning: NewLogPath,
+               LogLocationInfo:    OldAccessLogPath,
+               LogLocationEvent:   NewLogPath,
+               LogLocationDebug:   log.LogLocationNull,
+       }
+       err := error(nil)
+       if expected.TOURL, err = url.Parse(expected.TOURLStr); err != nil {
+               t.Errorf("expected URL parse '%+v' err nil actual %+v", 
expected.TOURLStr, err)
+       }
+
+       cfg, err := getPerlConfigsFromStrs(cdnConfInput, dbConfInput)
+       if err != nil {
+               t.Errorf("expected nil err actual %v", err)
+       }
+
+       if !reflect.DeepEqual(cfg, expected) {
+               t.Errorf("expected %+v actual %+v", expected, cfg)
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/8b0ac5f9/traffic_ops/traffic_ops_golang/traffic_ops_golang.go
----------------------------------------------------------------------
diff --git a/traffic_ops/traffic_ops_golang/traffic_ops_golang.go 
b/traffic_ops/traffic_ops_golang/traffic_ops_golang.go
index 8f70098..6d2c75b 100644
--- a/traffic_ops/traffic_ops_golang/traffic_ops_golang.go
+++ b/traffic_ops/traffic_ops_golang/traffic_ops_golang.go
@@ -34,17 +34,30 @@ const Version = "0.1"
 
 const DefaultConfigPath = "/opt/traffic_ops/traffic_ops_golang.config"
 
+const OldConfig = true
+const OldConfigCDNConfPath = "/opt/traffic_ops/app/conf/cdn.conf"
+const OldConfigDBConfPath = 
"/opt/traffic_ops/app/conf/production/database.conf"
+
 func main() {
        configFileName := flag.String("cfg", "", "The config file path")
+       oldConfig := flag.Bool("oldcfg", true, "Whether to look for old Perl 
Traffic Ops config files")
        flag.Parse()
        if *configFileName == "" {
                *configFileName = DefaultConfigPath
        }
 
-       cfg, err := LoadConfig(*configFileName)
-       if err != nil {
-               fmt.Println("Error loading config '" + *configFileName + "': " 
+ err.Error())
-               return
+       cfg := Config{}
+       err := error(nil)
+       if !*oldConfig {
+               if cfg, err = LoadConfig(*configFileName); err != nil {
+                       fmt.Println("Error loading config '" + *configFileName 
+ "': " + err.Error())
+                       return
+               }
+       } else {
+               if cfg, err = GetPerlConfigs(OldConfigCDNConfPath, 
OldConfigDBConfPath); err != nil {
+                       fmt.Println("Error loading old configs '" + 
OldConfigCDNConfPath + "' and '" + OldConfigDBConfPath + "': " + err.Error())
+                       return
+               }
        }
 
        if err := log.InitCfg(cfg); err != nil {

Reply via email to