You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by de...@apache.org on 2018/09/14 14:40:45 UTC

[trafficcontrol] branch master updated (5197a2d -> eca0a7e)

This is an automated email from the ASF dual-hosted git repository.

dewrich pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git.


    from 5197a2d  Remove TO unused func
     new 8ba7d24  Add TO Go steering/id/targets
     new 5ba9a3b  Add TO API Tests for steeringtargets
     new eca0a7e  Add TO Go client steeringtarget funcs

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 lib/go-tc/steeringtarget.go                        |   3 -
 traffic_ops/client/steeringtarget.go               |  96 ++++++
 .../testing/api/v13/steeringtargets_test.go        | 302 ++++++++++++++++++
 traffic_ops/testing/api/v13/tc-fixtures.json       |   8 +
 traffic_ops/testing/api/v13/traffic_control.go     |   1 +
 traffic_ops/traffic_ops_golang/routes.go           |   7 +
 .../steeringtargets/steeringtargets.go             | 337 +++++++++++++++++++++
 traffic_ops/traffic_ops_golang/tenant/tenancy.go   |  26 ++
 8 files changed, 777 insertions(+), 3 deletions(-)
 create mode 100644 traffic_ops/client/steeringtarget.go
 create mode 100644 traffic_ops/testing/api/v13/steeringtargets_test.go
 create mode 100644 traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets.go


[trafficcontrol] 02/03: Add TO API Tests for steeringtargets

Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dewrich pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git

commit 5ba9a3b40b59f6de2c40ad71c5a0a1a84d3acacf
Author: Robert Butts <ro...@apache.org>
AuthorDate: Tue Sep 11 09:22:08 2018 -0600

    Add TO API Tests for steeringtargets
---
 .../testing/api/v13/steeringtargets_test.go        | 302 +++++++++++++++++++++
 traffic_ops/testing/api/v13/tc-fixtures.json       |   8 +
 traffic_ops/testing/api/v13/traffic_control.go     |   1 +
 3 files changed, 311 insertions(+)

diff --git a/traffic_ops/testing/api/v13/steeringtargets_test.go b/traffic_ops/testing/api/v13/steeringtargets_test.go
new file mode 100644
index 0000000..5c28f62
--- /dev/null
+++ b/traffic_ops/testing/api/v13/steeringtargets_test.go
@@ -0,0 +1,302 @@
+package v13
+
+/*
+
+   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.
+*/
+
+import (
+	"testing"
+
+	"github.com/apache/trafficcontrol/lib/go-log"
+	"github.com/apache/trafficcontrol/lib/go-util"
+)
+
+func TestSteeringTargets(t *testing.T) {
+	CreateTestCDNs(t)
+	CreateTestTypes(t)
+	CreateTestProfiles(t)
+	CreateTestStatuses(t)
+	CreateTestDivisions(t)
+	CreateTestRegions(t)
+	CreateTestPhysLocations(t)
+	CreateTestCacheGroups(t)
+	CreateTestServers(t)
+	CreateTestDeliveryServices(t)
+
+	CreateTestSteeringTargets(t)
+	GetTestSteeringTargets(t)
+	UpdateTestSteeringTargets(t)
+	DeleteTestSteeringTargets(t)
+
+	DeleteTestDeliveryServices(t)
+	DeleteTestServers(t)
+	DeleteTestCacheGroups(t)
+	DeleteTestPhysLocations(t)
+	DeleteTestRegions(t)
+	DeleteTestDivisions(t)
+	DeleteTestStatuses(t)
+	DeleteTestProfiles(t)
+	DeleteTestTypes(t)
+	DeleteTestCDNs(t)
+}
+
+func CreateTestSteeringTargets(t *testing.T) {
+	log.Debugln("CreateTestSteeringTargets")
+	for _, st := range testData.SteeringTargets {
+		if st.Type == nil {
+			t.Fatalf("creating steering target: test data missing type\n")
+		}
+		if st.DeliveryService == nil {
+			t.Fatalf("creating steering target: test data missing ds\n")
+		}
+		if st.Target == nil {
+			t.Fatalf("creating steering target: test data missing target\n")
+		}
+
+		{
+			respTypes, _, err := TOSession.GetTypeByName(*st.Type)
+			if err != nil {
+				t.Fatalf("creating steering target: getting type: %v\n", err)
+			} else if len(respTypes) < 1 {
+				t.Fatalf("creating steering target: getting type: not found\n")
+			}
+			st.TypeID = util.IntPtr(respTypes[0].ID)
+		}
+		{
+			respDS, _, err := TOSession.GetDeliveryServiceByXMLID(string(*st.DeliveryService))
+			if err != nil {
+				t.Fatalf("creating steering target: getting ds: %v\n", err)
+			} else if len(respDS) < 1 {
+				t.Fatalf("creating steering target: getting ds: not found\n")
+			}
+			dsID := uint64(respDS[0].ID)
+			st.DeliveryServiceID = &dsID
+		}
+		{
+			respTarget, _, err := TOSession.GetDeliveryServiceByXMLID(string(*st.Target))
+			if err != nil {
+				t.Fatalf("creating steering target: getting target ds: %v\n", err)
+			} else if len(respTarget) < 1 {
+				t.Fatalf("creating steering target: getting target ds: not found\n")
+			}
+			targetID := uint64(respTarget[0].ID)
+			st.TargetID = &targetID
+		}
+
+		resp, _, err := TOSession.CreateSteeringTarget(st)
+		log.Debugln("Response: ", resp)
+		if err != nil {
+			t.Fatalf("creating steering target: %v\n", err)
+		}
+	}
+	log.Debugln("CreateTestSteeringTargets() PASSED")
+}
+
+func UpdateTestSteeringTargets(t *testing.T) {
+	log.Debugln("UpdateTestSteeringTargets")
+
+	if len(testData.SteeringTargets) < 1 {
+		t.Fatalf("updating steering target: no steering target test data\n")
+	}
+	st := testData.SteeringTargets[0]
+	if st.DeliveryService == nil {
+		t.Fatalf("updating steering target: test data missing ds\n")
+	}
+	if st.Target == nil {
+		t.Fatalf("updating steering target: test data missing target\n")
+	}
+
+	respDS, _, err := TOSession.GetDeliveryServiceByXMLID(string(*st.DeliveryService))
+	if err != nil {
+		t.Fatalf("updating steering target: getting ds: %v\n", err)
+	}
+	if len(respDS) < 1 {
+		t.Fatalf("updating steering target: getting ds: not found\n")
+	}
+	dsID := respDS[0].ID
+
+	sts, _, err := TOSession.GetSteeringTargets(dsID)
+	if err != nil {
+		t.Fatalf("updating steering targets: getting steering target: %v\n", err)
+	}
+	if len(sts) < 1 {
+		t.Fatalf("updating steering targets: getting steering target: got 0\n")
+	}
+	st = sts[0]
+
+	expected := uint64(12345)
+	if st.Value != nil && *st.Value == expected {
+		expected += 1
+	}
+	st.Value = &expected
+
+	_, _, err = TOSession.UpdateSteeringTarget(st)
+	if err != nil {
+		t.Fatalf("updating steering targets: updating: %+v\n", err)
+	}
+
+	sts, _, err = TOSession.GetSteeringTargets(dsID)
+	if err != nil {
+		t.Fatalf("updating steering targets: getting updated steering target: %v\n", err)
+	}
+	if len(sts) < 1 {
+		t.Fatalf("updating steering targets: getting updated steering target: got 0\n")
+	}
+	actual := sts[0]
+
+	if actual.DeliveryServiceID == nil {
+		t.Fatalf("steering target update: ds id expected %v actual %v\n", dsID, nil)
+	} else if *actual.DeliveryServiceID != uint64(dsID) {
+		t.Fatalf("steering target update: ds id expected %v actual %v\n", dsID, *actual.DeliveryServiceID)
+	}
+	if actual.TargetID == nil {
+		t.Fatalf("steering target update: ds id expected %v actual %v\n", dsID, nil)
+	} else if *actual.TargetID != *st.TargetID {
+		t.Fatalf("steering target update: ds id expected %v actual %v\n", *st.TargetID, *actual.TargetID)
+	}
+	if actual.TypeID == nil {
+		t.Fatalf("steering target update: ds id expected %v actual %v\n", *st.TypeID, nil)
+	} else if *actual.TypeID != *st.TypeID {
+		t.Fatalf("steering target update: ds id expected %v actual %v\n", *st.TypeID, *actual.TypeID)
+	}
+	if actual.DeliveryService == nil {
+		t.Fatalf("steering target update: ds expected %v actual %v\n", *st.DeliveryService, nil)
+	} else if *st.DeliveryService != *actual.DeliveryService {
+		t.Fatalf("steering target update: ds name expected %v actual %v\n", *st.DeliveryService, *actual.DeliveryService)
+	}
+	if actual.Target == nil {
+		t.Fatalf("steering target update: target expected %v actual %v\n", *st.Target, nil)
+	} else if *st.Target != *actual.Target {
+		t.Fatalf("steering target update: target expected %v actual %v\n", *st.Target, *actual.Target)
+	}
+	if actual.Type == nil {
+		t.Fatalf("steering target update: type expected %v actual %v\n", *st.Type, nil)
+	} else if *st.Type != *actual.Type {
+		t.Fatalf("steering target update: type expected %v actual %v\n", *st.Type, *actual.Type)
+	}
+	if actual.Value == nil {
+		t.Fatalf("steering target update: ds expected %v actual %v\n", *st.Value, nil)
+	} else if *st.Value != *actual.Value {
+		t.Fatalf("steering target update: value expected %v actual %v\n", *st.Value, actual.Value)
+	}
+	log.Debugln("UpdateTestSteeringTargets() PASSED")
+}
+
+func GetTestSteeringTargets(t *testing.T) {
+	log.Debugln("GetTestSteeringTargets")
+
+	if len(testData.SteeringTargets) < 1 {
+		t.Fatalf("updating steering target: no steering target test data\n")
+	}
+	st := testData.SteeringTargets[0]
+	if st.DeliveryService == nil {
+		t.Fatalf("updating steering target: test data missing ds\n")
+	}
+
+	respDS, _, err := TOSession.GetDeliveryServiceByXMLID(string(*st.DeliveryService))
+	if err != nil {
+		t.Fatalf("creating steering target: getting ds: %v\n", err)
+	} else if len(respDS) < 1 {
+		t.Fatalf("steering target get: getting ds: not found\n")
+	}
+	dsID := respDS[0].ID
+
+	sts, _, err := TOSession.GetSteeringTargets(dsID)
+	if err != nil {
+		t.Fatalf("steering target get: getting steering target: %v\n", err)
+	}
+
+	if len(sts) != len(testData.SteeringTargets) {
+		t.Fatalf("steering target get: expected %v actual %v\n", len(testData.SteeringTargets), len(sts))
+	}
+
+	expected := testData.SteeringTargets[0]
+	actual := sts[0]
+
+	if actual.DeliveryServiceID == nil {
+		t.Fatalf("steering target get: ds id expected %v actual %v\n", dsID, nil)
+	} else if *actual.DeliveryServiceID != uint64(dsID) {
+		t.Fatalf("steering target get: ds id expected %v actual %v\n", dsID, *actual.DeliveryServiceID)
+	}
+	if actual.DeliveryService == nil {
+		t.Fatalf("steering target get: ds expected %v actual %v\n", expected.DeliveryService, nil)
+	} else if *expected.DeliveryService != *actual.DeliveryService {
+		t.Fatalf("steering target get: ds name expected %v actual %v\n", expected.DeliveryService, actual.DeliveryService)
+	}
+	if actual.Target == nil {
+		t.Fatalf("steering target get: target expected %v actual %v\n", expected.Target, nil)
+	} else if *expected.Target != *actual.Target {
+		t.Fatalf("steering target get: target expected %v actual %v\n", expected.Target, actual.Target)
+	}
+	if actual.Type == nil {
+		t.Fatalf("steering target get: type expected %v actual %v\n", expected.Type, nil)
+	} else if *expected.Type != *actual.Type {
+		t.Fatalf("steering target get: type expected %v actual %v\n", expected.Type, actual.Type)
+	}
+	if actual.Value == nil {
+		t.Fatalf("steering target get: ds expected %v actual %v\n", expected.Value, nil)
+	} else if *expected.Value != *actual.Value {
+		t.Fatalf("steering target get: value expected %v actual %v\n", *expected.Value, *actual.Value)
+	}
+	log.Debugln("GetTestSteeringTargets() PASSED")
+}
+
+func DeleteTestSteeringTargets(t *testing.T) {
+	log.Debugln("DeleteTestSteeringTargets")
+	dsIDs := []uint64{}
+	for _, st := range testData.SteeringTargets {
+		if st.DeliveryService == nil {
+			t.Fatalf("deleting steering target: test data missing ds\n")
+		}
+		if st.Target == nil {
+			t.Fatalf("deleting steering target: test data missing target\n")
+		}
+
+		respDS, _, err := TOSession.GetDeliveryServiceByXMLID(string(*st.DeliveryService))
+		if err != nil {
+			t.Fatalf("deleting steering target: getting ds: %v\n", err)
+		} else if len(respDS) < 1 {
+			t.Fatalf("deleting steering target: getting ds: not found\n")
+		}
+		dsID := uint64(respDS[0].ID)
+		st.DeliveryServiceID = &dsID
+
+		dsIDs = append(dsIDs, dsID)
+
+		respTarget, _, err := TOSession.GetDeliveryServiceByXMLID(string(*st.Target))
+		if err != nil {
+			t.Fatalf("deleting steering target: getting target ds: %v\n", err)
+		} else if len(respTarget) < 1 {
+			t.Fatalf("deleting steering target: getting target ds: not found\n")
+		}
+		targetID := uint64(respTarget[0].ID)
+		st.TargetID = &targetID
+
+		_, _, err = TOSession.DeleteSteeringTarget(int(*st.DeliveryServiceID), int(*st.TargetID))
+		if err != nil {
+			t.Fatalf("deleting steering target: deleting: %+v\n", err)
+		}
+	}
+
+	for _, dsID := range dsIDs {
+		sts, _, err := TOSession.GetSteeringTargets(int(dsID))
+		if err != nil {
+			t.Fatalf("deleting steering targets: getting steering target: %v\n", err)
+		}
+		if len(sts) != 0 {
+			t.Fatalf("deleting steering targets: after delete, getting steering target: expected 0 actual %+v\n", len(sts))
+		}
+	}
+	log.Debugln("DeleteTestSteeringTargets() PASSED")
+}
diff --git a/traffic_ops/testing/api/v13/tc-fixtures.json b/traffic_ops/testing/api/v13/tc-fixtures.json
index dbb5347..1a6a58b 100644
--- a/traffic_ops/testing/api/v13/tc-fixtures.json
+++ b/traffic_ops/testing/api/v13/tc-fixtures.json
@@ -1436,5 +1436,13 @@
             "uid": 0,
             "username": "federationuser"
         }
+    ],
+    "steeringTargets": [
+        {
+            "deliveryService": "ds1",
+            "target": "ds2",
+            "value": 42,
+            "type": "STEERING_WEIGHT"
+        }
     ]
 }
diff --git a/traffic_ops/testing/api/v13/traffic_control.go b/traffic_ops/testing/api/v13/traffic_control.go
index ba96dcb..625855c 100644
--- a/traffic_ops/testing/api/v13/traffic_control.go
+++ b/traffic_ops/testing/api/v13/traffic_control.go
@@ -42,4 +42,5 @@ type TrafficControl struct {
 	StaticDNSEntries               []tc.StaticDNSEntry                `json:"staticdnsentries"`
 	Tenants                        []tc.Tenant                        `json:"tenants"`
 	Types                          []tc.Type                          `json:"types"`
+	SteeringTargets                []tc.SteeringTargetNullable        `json:"steeringTargets"`
 }


[trafficcontrol] 01/03: Add TO Go steering/id/targets

Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dewrich pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git

commit 8ba7d24303d2b420d5059654f83a7154ff7a0703
Author: Robert Butts <ro...@apache.org>
AuthorDate: Tue Jul 10 08:29:21 2018 -0600

    Add TO Go steering/id/targets
---
 lib/go-tc/steeringtarget.go                        |   3 -
 traffic_ops/traffic_ops_golang/routes.go           |   7 +
 .../steeringtargets/steeringtargets.go             | 337 +++++++++++++++++++++
 traffic_ops/traffic_ops_golang/tenant/tenancy.go   |  26 ++
 4 files changed, 370 insertions(+), 3 deletions(-)

diff --git a/lib/go-tc/steeringtarget.go b/lib/go-tc/steeringtarget.go
index 17feaa3..e04c63d 100644
--- a/lib/go-tc/steeringtarget.go
+++ b/lib/go-tc/steeringtarget.go
@@ -47,9 +47,6 @@ type SteeringTargetNullable struct {
 
 func (st SteeringTargetNullable) Validate(tx *sql.Tx) error {
 	errs := []string{}
-	if st.TargetID == nil {
-		errs = append(errs, "missing target")
-	}
 	if st.TypeID == nil {
 		errs = append(errs, "missing typeId")
 	}
diff --git a/traffic_ops/traffic_ops_golang/routes.go b/traffic_ops/traffic_ops_golang/routes.go
index f49164e..f9c2c84 100644
--- a/traffic_ops/traffic_ops_golang/routes.go
+++ b/traffic_ops/traffic_ops_golang/routes.go
@@ -63,6 +63,7 @@ import (
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/server"
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/staticdnsentry"
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/status"
+	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/steeringtargets"
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/systeminfo"
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/types"
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/user"
@@ -386,6 +387,12 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) {
 		{1.1, http.MethodGet, `deliveryservices/xmlId/{name}/urlkeys/?(\.json)?$`, deliveryservice.GetURLKeysByName, auth.PrivLevelReadOnly, Authenticated, nil},
 		{1.1, http.MethodGet, `deliveryservices/{id}/urlkeys/?(\.json)?$`, deliveryservice.GetURLKeysByID, auth.PrivLevelReadOnly, Authenticated, nil},
 		{1.1, http.MethodGet, `riak/bucket/{bucket}/key/{key}/values/?(\.json)?$`, apiriak.GetBucketKey, auth.PrivLevelAdmin, Authenticated, nil},
+
+		{1.1, http.MethodGet, `steering/{deliveryservice}/targets/?(\.json)?$`, api.ReadHandler(steeringtargets.TypeFactory), auth.PrivLevelReadOnly, Authenticated, nil},
+		{1.1, http.MethodGet, `steering/{deliveryservice}/targets/{target}$`, api.ReadHandler(steeringtargets.TypeFactory), auth.PrivLevelReadOnly, Authenticated, nil},
+		{1.1, http.MethodPost, `steering/{deliveryservice}/targets/?(\.json)?$`, api.CreateHandler(steeringtargets.TypeFactory), auth.PrivLevelOperations, Authenticated, nil},
+		{1.1, http.MethodPut, `steering/{deliveryservice}/targets/{target}/?(\.json)?$`, api.UpdateHandler(steeringtargets.TypeFactory), auth.PrivLevelOperations, Authenticated, nil},
+		{1.1, http.MethodDelete, `steering/{deliveryservice}/targets/{target}/?(\.json)?$`, api.DeleteHandler(steeringtargets.TypeFactory), auth.PrivLevelOperations, Authenticated, nil},
 	}
 
 	// rawRoutes are served at the root path. These should be almost exclusively old Perl pre-API routes, which have yet to be converted in all clients. New routes should be in the versioned API path.
diff --git a/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets.go b/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets.go
new file mode 100644
index 0000000..9642983
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets.go
@@ -0,0 +1,337 @@
+package steeringtargets
+
+/*
+ * 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 (
+	"errors"
+	"fmt"
+	"net/http"
+	"strconv"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+	"github.com/apache/trafficcontrol/lib/go-util"
+	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
+	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth"
+	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
+	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
+
+	"github.com/jmoiron/sqlx"
+)
+
+type TOSteeringTargetV11 struct {
+	ReqInfo *api.APIInfo `json:"-"`
+	tc.SteeringTargetNullable
+	DSTenantID  *int          `json:"-" db:"tenant"`
+	LastUpdated *tc.TimeNoMod `json:"-" db:"last_updated"`
+}
+
+func TypeFactory(inf *api.APIInfo) api.CRUDer {
+	return &TOSteeringTargetV11{ReqInfo: inf}
+}
+
+func (st TOSteeringTargetV11) GetKeyFieldsInfo() []api.KeyFieldInfo {
+	return []api.KeyFieldInfo{
+		{"deliveryservice", api.GetIntKey},
+		{"target", api.GetIntKey},
+	}
+}
+
+func (st TOSteeringTargetV11) GetKeys() (map[string]interface{}, bool) {
+	keys := map[string]interface{}{}
+	valid := true
+	if st.DeliveryServiceID == nil {
+		keys["deliveryservice"] = 0
+		valid = false
+	} else {
+		keys["deliveryservice"] = int(*st.DeliveryServiceID)
+	}
+	if st.TargetID == nil {
+		keys["target"] = 0
+		valid = false
+	} else {
+		keys["target"] = int(*st.TargetID)
+	}
+	return keys, valid
+}
+
+func (st *TOSteeringTargetV11) SetKeys(keys map[string]interface{}) {
+	dsI, _ := keys["deliveryservice"].(int) //this utilizes the non panicking type assertion, if the thrown away ok variable is false i will be the zero of the type, 0 here.
+	ds := uint64(dsI)
+	st.DeliveryServiceID = &ds
+	targetI, _ := keys["target"].(int) //this utilizes the non panicking type assertion, if the thrown away ok variable is false i will be the zero of the type, 0 here.
+	target := uint64(targetI)
+	st.TargetID = &target
+}
+
+func (st TOSteeringTargetV11) GetAuditName() string {
+	if st.DeliveryService != nil && st.Target != nil {
+		return string(*st.DeliveryService) + `-` + string(*st.Target)
+	}
+	if st.DeliveryServiceID != nil && st.TargetID != nil {
+		return strconv.FormatUint(*st.DeliveryServiceID, 10) + `-` + strconv.FormatUint(*st.TargetID, 10)
+	}
+	return "unknown"
+}
+
+func (st TOSteeringTargetV11) GetType() string {
+	return "steeringtarget"
+}
+
+func (st TOSteeringTargetV11) Validate() error {
+	return st.SteeringTargetNullable.Validate(st.ReqInfo.Tx.Tx)
+}
+
+func (st *TOSteeringTargetV11) Read() ([]interface{}, error, error, int) {
+	steeringTargets, userErr, sysErr, errCode := read(st.ReqInfo.Tx, st.ReqInfo.Params, st.ReqInfo.User)
+	if userErr != nil || sysErr != nil {
+		return nil, userErr, sysErr, errCode
+	}
+	iSteeringTargets := make([]interface{}, len(steeringTargets), len(steeringTargets))
+	for i, steeringTarget := range steeringTargets {
+		iSteeringTargets[i] = steeringTarget
+	}
+	return iSteeringTargets, nil, nil, http.StatusOK
+}
+
+func read(tx *sqlx.Tx, parameters map[string]string, user *auth.CurrentUser) ([]tc.SteeringTargetNullable, error, error, int) {
+	queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+		"deliveryservice": dbhelpers.WhereColumnInfo{"st.deliveryservice", api.IsInt},
+		"target":          dbhelpers.WhereColumnInfo{"st.target", api.IsInt},
+	}
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(parameters, queryParamsToQueryCols)
+	if len(errs) > 0 {
+		return nil, nil, util.JoinErrs(errs), http.StatusBadRequest
+	}
+	query := selectQuery() + where + orderBy
+
+	userTenants, err := tenant.GetUserTenantListTx(*user, tx.Tx)
+	if err != nil {
+		return nil, nil, errors.New("getting user tenant list: " + err.Error()), http.StatusInternalServerError
+	}
+
+	rows, err := tx.NamedQuery(query, queryValues)
+	if err != nil {
+		return nil, nil, errors.New("steering targets querying: " + err.Error()), http.StatusInternalServerError
+	}
+	defer rows.Close()
+
+	steeringTargets := []TOSteeringTargetV11{}
+	for rows.Next() {
+		s := TOSteeringTargetV11{}
+		if err = rows.StructScan(&s); err != nil {
+			return nil, nil, errors.New("steering targets parsing: " + err.Error()), http.StatusInternalServerError
+		}
+		steeringTargets = append(steeringTargets, s)
+	}
+
+	tenantMap := map[int]struct{}{}
+	for _, ten := range userTenants {
+		if ten.ID == nil {
+			return nil, nil, errors.New("user tenant with nil ID"), http.StatusInternalServerError
+		}
+		tenantMap[*ten.ID] = struct{}{}
+	}
+
+	filteredTargets := []tc.SteeringTargetNullable{}
+	for _, tr := range steeringTargets {
+		if tr.DSTenantID == nil {
+			filteredTargets = append(filteredTargets, tr.SteeringTargetNullable)
+			continue
+		}
+		if _, ok := tenantMap[int(*tr.DSTenantID)]; ok {
+			filteredTargets = append(filteredTargets, tr.SteeringTargetNullable)
+			continue
+		}
+	}
+	return filteredTargets, nil, nil, http.StatusOK
+}
+
+func (st *TOSteeringTargetV11) Create() (error, error, int) {
+	dsIDInt, err := strconv.Atoi(st.ReqInfo.Params["deliveryservice"])
+	if err != nil {
+		return errors.New("delivery service ID must be an integer"), nil, http.StatusBadRequest
+	}
+	dsID := uint64(dsIDInt)
+	st.DeliveryServiceID = &dsID
+
+	// target can't be in the Validate func, because it's in the parameters of PUT, not the body (but it is in the body in the POST here).
+	if st.TargetID == nil {
+		return errors.New("missing target"), nil, http.StatusBadRequest
+	}
+
+	if userErr, sysErr, errCode := tenant.CheckID(st.ReqInfo.Tx.Tx, st.ReqInfo.User, int(*st.DeliveryServiceID)); userErr != nil || sysErr != nil {
+		return userErr, sysErr, errCode
+	}
+
+	rows, err := st.ReqInfo.Tx.NamedQuery(insertQuery(), st)
+	if err != nil {
+		return api.ParseDBErr(err, st.GetType())
+	}
+	defer rows.Close()
+
+	rowsAffected := 0
+	for rows.Next() {
+		rowsAffected++
+		if err = rows.StructScan(&st); err != nil {
+			return nil, errors.New("steering target create scanning: " + err.Error()), http.StatusInternalServerError
+		}
+	}
+	if rowsAffected == 0 {
+		return nil, errors.New("no " + st.GetType() + " was inserted, no id was returned"), http.StatusInternalServerError
+	} else if rowsAffected > 1 {
+		return nil, errors.New("too many ids returned from steering target insert"), http.StatusInternalServerError
+	}
+	return nil, nil, http.StatusOK
+}
+
+func (st *TOSteeringTargetV11) Update() (error, error, int) {
+	dsIDInt, err := strconv.Atoi(st.ReqInfo.Params["deliveryservice"])
+	if err != nil {
+		return errors.New("delivery service ID must be an integer"), nil, http.StatusBadRequest
+	}
+	dsID := uint64(dsIDInt)
+	// TODO determine if the CRUDer automatically does this
+	st.DeliveryServiceID = &dsID
+
+	targetIDInt, err := strconv.Atoi(st.ReqInfo.Params["target"])
+	if err != nil {
+		return errors.New("target ID must be an integer"), nil, http.StatusBadRequest
+	}
+	targetID := uint64(targetIDInt)
+	st.TargetID = &targetID
+
+	if userErr, sysErr, errCode := tenant.CheckID(st.ReqInfo.Tx.Tx, st.ReqInfo.User, int(*st.DeliveryServiceID)); userErr != nil || sysErr != nil {
+		return userErr, sysErr, errCode
+	}
+
+	rows, err := st.ReqInfo.Tx.NamedQuery(updateQuery(), st)
+	if err != nil {
+		return api.ParseDBErr(err, st.GetType())
+	}
+	defer rows.Close()
+
+	lastUpdated := tc.TimeNoMod{}
+	rowsAffected := 0
+	for rows.Next() {
+		rowsAffected++
+		if err = rows.StructScan(&st); err != nil {
+			return nil, errors.New("steering target update scanning: " + err.Error()), http.StatusInternalServerError
+		}
+	}
+	st.LastUpdated = &lastUpdated
+	if rowsAffected != 1 {
+		if rowsAffected < 1 {
+			return nil, nil, http.StatusNotFound
+		}
+		return nil, errors.New("too many ids returned from steering target update"), http.StatusInternalServerError
+	}
+	return nil, nil, http.StatusOK
+}
+
+func (st *TOSteeringTargetV11) Delete() (error, error, int) {
+	if userErr, sysErr, errCode := tenant.CheckID(st.ReqInfo.Tx.Tx, st.ReqInfo.User, int(*st.DeliveryServiceID)); userErr != nil || sysErr != nil {
+		return userErr, sysErr, errCode
+	}
+
+	result, err := st.ReqInfo.Tx.NamedExec(deleteQuery(), st)
+	if err != nil {
+		return nil, errors.New("steering target delete exec: " + err.Error()), http.StatusInternalServerError
+	}
+	rowsAffected, err := result.RowsAffected()
+	if err != nil {
+		return nil, errors.New("steering target delete exec getting rows affected: " + err.Error()), http.StatusInternalServerError
+	}
+
+	if rowsAffected < 1 {
+		return nil, nil, http.StatusNotFound
+	} else if rowsAffected != 1 {
+		return nil, fmt.Errorf("this create affected too many rows: %d", rowsAffected), http.StatusInternalServerError
+	}
+	return nil, nil, http.StatusOK
+}
+
+func selectQuery() string {
+	return `
+SELECT
+  st.deliveryservice,
+  ds.xml_id as deliveryservice_name,
+  CAST(ds.tenant_id AS INTEGER) as tenant,
+  st.target,
+  dst.xml_id AS target_name,
+  st.type as type_id,
+  tp.name as type_name,
+  st.value
+FROM steering_target AS st
+JOIN deliveryservice AS ds ON st.deliveryservice = ds.id
+JOIN deliveryservice AS dst ON st.target = dst.id
+JOIN type AS tp ON tp.id = st.type
+`
+}
+
+func insertQuery() string {
+	return `
+WITH st AS (
+  INSERT INTO steering_target (deliveryservice, target, value, type)
+  VALUES (:deliveryservice, :target, :value, :type_id)
+  RETURNING deliveryservice, target, value, type
+)
+SELECT
+  st.deliveryservice,
+  ds.xml_id as deliveryservice_name,
+  st.target,
+  dst.xml_id AS target_name,
+  st.type as type_id,
+  tp.name as type_name,
+  st.value
+FROM st
+JOIN deliveryservice AS ds ON st.deliveryservice = ds.id
+JOIN deliveryservice AS dst ON st.target = dst.id
+JOIN type AS tp ON tp.id = st.type
+`
+}
+
+func updateQuery() string {
+	return `
+WITH st as (
+  UPDATE steering_target SET
+    value = :value,
+    type = :type_id
+  WHERE deliveryservice = :deliveryservice AND target = :target
+  RETURNING deliveryservice, target, value, type, last_updated
+)
+SELECT
+  st.deliveryservice,
+  ds.xml_id as deliveryservice_name,
+  st.target,
+  dst.xml_id AS target_name,
+  st.type as type_id,
+  tp.name as type_name,
+  st.value,
+  st.last_updated
+FROM st
+JOIN deliveryservice AS ds ON st.deliveryservice = ds.id
+JOIN deliveryservice AS dst ON st.target = dst.id
+JOIN type AS tp ON tp.id = st.type
+`
+}
+
+func deleteQuery() string {
+	return `DELETE FROM steering_target WHERE deliveryservice = :deliveryservice AND target = :target`
+}
diff --git a/traffic_ops/traffic_ops_golang/tenant/tenancy.go b/traffic_ops/traffic_ops_golang/tenant/tenancy.go
index c897f2d..e57a4df 100644
--- a/traffic_ops/traffic_ops_golang/tenant/tenancy.go
+++ b/traffic_ops/traffic_ops_golang/tenant/tenancy.go
@@ -110,6 +110,32 @@ func CheckID(tx *sql.Tx, user *auth.CurrentUser, dsID int) (error, error, int) {
 	return nil, nil, http.StatusOK
 }
 
+// GetUserTenantListTx returns a Tenant list that the specified user has access to.
+// NOTE: This method does not use the use_tenancy parameter and if this method is being used
+// to control tenancy the parameter must be checked. The method IsResourceAuthorizedToUser checks the use_tenancy parameter
+// and should be used for this purpose in most cases.
+func GetUserTenantListTx(user auth.CurrentUser, tx *sql.Tx) ([]tc.TenantNullable, error) {
+	query := `WITH RECURSIVE q AS (SELECT id, name, active, parent_id, last_updated FROM tenant WHERE id = $1
+	UNION SELECT t.id, t.name, t.active, t.parent_id, t.last_updated  FROM tenant t JOIN q ON q.id = t.parent_id)
+	SELECT id, name, active, parent_id, last_updated FROM q;`
+
+	rows, err := tx.Query(query, user.TenantID)
+	if err != nil {
+		return nil, errors.New("querying user tenant list: " + err.Error())
+	}
+	defer rows.Close()
+
+	tenants := []tc.TenantNullable{}
+	for rows.Next() {
+		t := tc.TenantNullable{}
+		if err := rows.Scan(&t.ID, &t.Name, &t.Active, &t.ParentID, &t.LastUpdated); err != nil {
+			return nil, err
+		}
+		tenants = append(tenants, t)
+	}
+	return tenants, nil
+}
+
 func GetUserTenantIDListTx(tx *sql.Tx, userTenantID int) ([]int, error) {
 	query := `
 WITH RECURSIVE q AS (SELECT id, name, active, parent_id FROM tenant WHERE id = $1


[trafficcontrol] 03/03: Add TO Go client steeringtarget funcs

Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dewrich pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git

commit eca0a7eab65cd37d6e4f0658c7640200b2e9ecda
Author: Robert Butts <ro...@apache.org>
AuthorDate: Wed Sep 12 11:33:39 2018 -0600

    Add TO Go client steeringtarget funcs
---
 traffic_ops/client/steeringtarget.go | 96 ++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

diff --git a/traffic_ops/client/steeringtarget.go b/traffic_ops/client/steeringtarget.go
new file mode 100644
index 0000000..bb5c7d5
--- /dev/null
+++ b/traffic_ops/client/steeringtarget.go
@@ -0,0 +1,96 @@
+/*
+
+   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 client
+
+import (
+	"encoding/json"
+	"errors"
+	"net/http"
+	"strconv"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+func (to *Session) CreateSteeringTarget(st tc.SteeringTargetNullable) (tc.Alerts, ReqInf, error) {
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
+	if st.DeliveryServiceID == nil {
+		return tc.Alerts{}, reqInf, errors.New("missing delivery service id")
+	}
+	reqBody, err := json.Marshal(st)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+
+	resp := (*http.Response)(nil)
+	if resp, reqInf.RemoteAddr, err = to.request(http.MethodPost, apiBase+`/steering/`+strconv.Itoa(int(*st.DeliveryServiceID))+`/targets`, reqBody); err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	alerts := tc.Alerts{}
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+func (to *Session) UpdateSteeringTarget(st tc.SteeringTargetNullable) (tc.Alerts, ReqInf, error) {
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
+	if st.DeliveryServiceID == nil {
+		return tc.Alerts{}, reqInf, errors.New("missing delivery service id")
+	}
+	if st.TargetID == nil {
+		return tc.Alerts{}, reqInf, errors.New("missing target id")
+	}
+
+	reqBody, err := json.Marshal(st)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp := (*http.Response)(nil)
+	resp, reqInf.RemoteAddr, err = to.request(http.MethodPut, apiBase+`/steering/`+strconv.Itoa(int(*st.DeliveryServiceID))+`/targets/`+strconv.Itoa(int(*st.TargetID)), reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	alerts := tc.Alerts{}
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+func (to *Session) GetSteeringTargets(dsID int) ([]tc.SteeringTargetNullable, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, apiBase+`/steering/`+strconv.Itoa(dsID)+`/targets`, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	data := struct {
+		Response []tc.SteeringTargetNullable `json:"response"`
+	}{}
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+func (to *Session) DeleteSteeringTarget(dsID int, targetID int) (tc.Alerts, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodDelete, apiBase+`/steering/`+strconv.Itoa(dsID)+`/targets/`+strconv.Itoa(targetID), nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	alerts := tc.Alerts{}
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}