<commit_before>// Copyright (c) 2016 <NAME>
// All Rights Reserved.
//
// 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 policy

import (
	"fmt"
	"github.com/romana/core/common"
	"github.com/romana/core/tenant"
	"log"
	"strconv"
	"strings"
	"crypto/sha1"
	"encoding/hex"
)

// Policy provides Policy service.
type PolicySvc struct {
	client *common.RestClient
	config common.ServiceConfig
	store  policyStore
}

const (
	infoListPath       = "/info"
	findPath           = "/find"
	policiesPath       = "/policies"
	policyNameQueryVar = "policyName"
)

func (policy *PolicySvc) Routes() common.Routes {
	routes := common.Routes{
		common.Route{
			Method:          "POST",
			Pattern:         policiesPath,
			Handler:         policy.addPolicy,
			MakeMessage:     func() interface{} { return &common.Policy{} },
			UseRequestToken: false,
		},
		common.Route{
			Method:          "DELETE",
			Pattern:         policiesPath,
			Handler:         policy.deletePolicyHandler,
			MakeMessage:     func() interface{} { return &common.Policy{} },
			UseRequestToken: false,
		},
		common.Route{
			Method:          "DELETE",
			Pattern:         policiesPath + "/{policyID}",
			Handler:         policy.deletePolicyHandler,
			MakeMessage:     func() interface{} { return &common.Policy{} },
			UseRequestToken: false,
		},
		common.Route{
			Method:          "GET",
			Pattern:         policiesPath,
			Handler:         policy.listPolicies,
			MakeMessage:     nil,
			UseRequestToken: false,
		},
		common.Route{
			Method:          "GET",
			Pattern:         policiesPath + "/{policyID}",
			Handler:         policy.getPolicy,
			MakeMessage:     nil,
			UseRequestToken: false,
		},
		common.Route{
			Method:  "GET",
			Pattern: findPath + policiesPath + "/{policyName}",
			Handler: policy.findPolicyByName,
		},
	}
	return routes
}

// augmentEndpoint augments the endpoint provided with appropriate information
// by looking it up in the appropriate service.
func (policy *PolicySvc) augmentEndpoint(endpoint *common.Endpoint) error {
	tenantSvcUrl, err := policy.client.GetServiceUrl("tenant")
	if err != nil {
		return err
	}
	if endpoint.Peer == common.Wildcard {
		// If a wildcard is specfied, there is nothing to augment
		return nil
	}
	log.Printf("Policy: Augmenting  %#v", endpoint)

	// Code below tries to resolve tenant name into tenant_network_id if possible.
	//
	// TODO this will have to be changed once we implement
	// https://paninetworks.kanbanize.com/ctrl_board/3/cards/319/details
	ten := &tenant.Tenant{}
	if endpoint.TenantNetworkID == nil {
		if endpoint.TenantID != 0 {
			tenantIDToUse := strconv.FormatUint(endpoint.TenantID, 10)
			tenantsUrl := fmt.Sprintf("%s/tenants/%s", tenantSvcUrl, tenantIDToUse)
			log.Printf("Policy: Looking tenant up at %s", tenantsUrl)
			err = policy.client.Get(tenantsUrl, ten)
			if err != nil {
				return err
			}

			endpoint.TenantNetworkID = &ten.Seq

		} else if endpoint.TenantExternalID != "" || endpoint.TenantName != "" {
			if endpoint.TenantExternalID != "" {
				ten.ExternalID = endpoint.TenantExternalID
			}
			if endpoint.TenantName != "" {
				ten.Name = endpoint.TenantName
			}
			err = policy.client.Find(ten, common.FindLast)
			if err != nil {
				return err
			}

			endpoint.TenantNetworkID = &ten.Seq
		}
	}

	if endpoint.SegmentNetworkID == nil {
		if ten == nil && (endpoint.SegmentID != 0 || endpoint.SegmentExternalID != "" || endpoint.SegmentName != "") {
			return common.NewError400("No tenant information specified, cannot look up segment.")
		}
		segment := &tenant.Segment{}
		if endpoint.SegmentID != 0 {
			segmentIDToUse := strconv.FormatUint(endpoint.SegmentID, 10)
			segmentsUrl := fmt.Sprintf("%s/tenants/%d/segments/%s", tenantSvcUrl, ten.ID, segmentIDToUse)
			log.Printf("Policy: Looking segment up at %s for %#v", segmentsUrl, endpoint)
			err = policy.client.Get(segmentsUrl, &segment)
			if err != nil {
				return err
			}
			endpoint.SegmentNetworkID = &segment.Seq
		} else if endpoint.SegmentExternalID != "" || endpoint.SegmentName != "" {
			segmentsUrl := fmt.Sprintf("%s/findLast/segments?tenant_id=%d&", tenantSvcUrl, ten.ID)
			if endpoint.SegmentExternalID != "" {
				segmentsUrl += "external_id=" + endpoint.TenantExternalID + "&"
			}
			if endpoint.SegmentName != "" {
				segmentsUrl += "name=" + endpoint.SegmentName
			}
			log.Printf("Policy: Finding segments at %s for %#v (Tenant %#v %t)", segmentsUrl, endpoint, ten, ten == nil)
			err = policy.client.Get(segmentsUrl, &segment)
			if err != nil {
				return err
			}
			endpoint.SegmentNetworkID = &segment.Seq
		}
	}
	return nil
}

// augmentPolicy augments the provided policy with information gotten from
// various services.
func (policy *PolicySvc) augmentPolicy(policyDoc *common.Policy) error {
	// Get info from topology service<commit_msg>Use NetworkID instead of seq, following after 6319a1<commit_after>// Copyright (c) 2016 Pani Networks
// All Rights Reserved.
//
// 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 policy

import (
	"fmt"
	"github.com/romana/core/common"
	"github.com/romana/core/tenant"
	"log"
	"strconv"
	"strings"
	"crypto/sha1"
	"encoding/hex"
)

// Policy provides Policy service.
type PolicySvc struct {
	client *common.RestClient
	config common.ServiceConfig
	store  policyStore
}

const (
	infoListPath       = "/info"
	findPath           = "/find"
	policiesPath       = "/policies"
	policyNameQueryVar = "policyName"
)

func (policy *PolicySvc) Routes() common.Routes {
	routes := common.Routes{
		common.Route{
			Method:          "POST",
			Pattern:         policiesPath,
			Handler:         policy.addPolicy,
			MakeMessage:     func() interface{} { return &common.Policy{} },
			UseRequestToken: false,
		},
		common.Route{
			Method:          "DELETE",
			Pattern:         policiesPath,
			Handler:         policy.deletePolicyHandler,
			MakeMessage:     func() interface{} { return &common.Policy{} },
			UseRequestToken: false,
		},
		common.Route{
			Method:          "DELETE",
			Pattern:         policiesPath + "/{policyID}",
			Handler:         policy.deletePolicyHandler,
			MakeMessage:     func() interface{} { return &common.Policy{} },
			UseRequestToken: false,
		},
		common.Route{
			Method:          "GET",
			Pattern:         policiesPath,
			Handler:         policy.listPolicies,
			MakeMessage:     nil,
			UseRequestToken: false,
		},
		common.Route{
			Method:          "GET",
			Pattern:         policiesPath + "/{policyID}",
			Handler:         policy.getPolicy,
			MakeMessage:     nil,
			UseRequestToken: false,
		},
		common.Route{
			Method:  "GET",
			Pattern: findPath + policiesPath + "/{policyName}",
			Handler: policy.findPolicyByName,
		},
	}
	return routes
}

// augmentEndpoint augments the endpoint provided with appropriate information
// by looking it up in the appropriate service.
func (policy *PolicySvc) augmentEndpoint(endpoint *common.Endpoint) error {
	tenantSvcUrl, err := policy.client.GetServiceUrl("tenant")
	if err != nil {
		return err
	}
	if endpoint.Peer == common.Wildcard {
		// If a wildcard is specfied, there is nothing to augment
		return nil
	}
	log.Printf("Policy: Augmenting  %#v", endpoint)

	// Code below tries to resolve tenant name into tenant_network_id if possible.
	//
	// TODO this will have to be changed once we implement
	// https://paninetworks.kanbanize.com/ctrl_board/3/cards/319/details
	ten := &tenant.Tenant{}
	if endpoint.TenantNetworkID == nil {
		if endpoint.TenantID != 0 {
			tenantIDToUse := strconv.FormatUint(endpoint.TenantID, 10)
			tenantsUrl := fmt.Sprintf("%s/tenants/%s", tenantSvcUrl, tenantIDToUse)
			log.Printf("Policy: Looking tenant up at %s", tenantsUrl)
			err = policy.client.Get(tenantsUrl, ten)
			if err != nil {
				return err
			}

			endpoint.TenantNetworkID = &ten.NetworkID

		} else if endpoint.TenantExternalID != "" || endpoint.TenantName != "" {
			if endpoint.TenantExternalID != "" {
				ten.ExternalID = endpoint.TenantExternalID
			}
			if endpoint.TenantName != "" {
				ten.Name = endpoint.TenantName
			}
			err = policy.client.Find(ten, common.FindLast)
			if err != nil {
				return err
			}

			endpoint.TenantNetworkID = &ten.NetworkID
		}
	}

	if endpoint.SegmentNetworkID == nil {
		if ten == nil && (endpoint.SegmentID != 0 || endpoint.SegmentExternalID != "" || endpoint.SegmentName != "") {
			return common.NewError400("No tenant information specified, cannot look up segment.")
		}
		segment := &tenant.Segment{}
		if endpoint.SegmentID != 0 {
			segmentIDToUse := strconv.FormatUint(endpoint.SegmentID, 10)
			segmentsUrl := fmt.Sprintf("%s/tenants/%d/segments/%s", tenantSvcUrl, ten.ID, segmentIDToUse)
			log.Printf("Policy: Looking segment up at %s for %#v", segmentsUrl, endpoint)
			err = policy.client.Get(segmentsUrl, &segment)
			if err != nil {
				return err
			}
			endpoint.SegmentNetworkID = &segment.NetworkID
		} else if endpoint.SegmentExternalID != "" || endpoint.SegmentName != "" {
			segmentsUrl := fmt.Sprintf("%s/findLast/segments?tenant_id=%d&", tenantSvcUrl, ten.ID)
			if endpoint.SegmentExternalID != "" {
				segmentsUrl += "external_id=" + endpoint.TenantExternalID + "&"
			}
			if endpoint.SegmentName != "" {
				segmentsUrl += "name=" + endpoint.SegmentName
			}
			log.Printf("Policy: Finding segments at %s for %#v (Tenant %#v %t)", segmentsUrl, endpoint, ten, ten == nil)
			err = policy.client.Get(segmentsUrl, &segment)
			if err != nil {
				return err
			}
			endpoint.SegmentNetworkID = &segment.NetworkID
		}
	}
	return nil
}

// augmentPolicy augments the provided policy with information gotten from
// various services.
func (policy *PolicySvc) augmentPolicy(policyDoc *common.Policy) error {
	// Get info from topology service
{'fraction_non_alphanumeric': 0.12193080357142858, 'fraction_numerical': 0.004743303571428571, 'mean_word_length': 3.255243371586862, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7173122', 'n_tokens_mistral': 3629, 'n_tokens_neox': 3286, 'n_words': 903}