Skip to content

Commit

Permalink
Merge pull request #11 from paninetworks/feature/gg/find
Browse files Browse the repository at this point in the history
This PR is against feature/gg/external_id
  • Loading branch information
pritesh authored Jun 17, 2016
2 parents ab46ef8 + 08de184 commit 408c3c7
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 230 deletions.
77 changes: 77 additions & 0 deletions common/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"net/http"
"net/url"
"reflect"
"strings"
"time"
)

Expand Down Expand Up @@ -154,6 +155,82 @@ func (rc *RestClient) ListHosts() ([]Host, error) {
return hostList, err
}

// FindOne is a convenience function, which queries the appropriate service
// and retrieves one entity based on provided structure, and puts the results
// into the same structure. The provided argument, entity, should be a pointer
// to the desired structure, e.g., &common.Host{}.
func (rc *RestClient) FindOne(entity interface{}) error {
structType := reflect.TypeOf(entity).Elem()
entityName := structType.String()
entityDottedNames := strings.Split(entityName, ".")
if len(entityDottedNames) > 1 {
entityName = entityDottedNames[1]
}
entityName = strings.ToLower(entityName)
var serviceName string
switch entityName {
case "tenant":
serviceName = "tenant"
case "segment":
serviceName = "tenant"
case "host":
serviceName = "topology"
default:
return NewError("Do not know where to find entity '%s'", entityName)
}

svcURL, err := rc.GetServiceUrl(serviceName)
if err != nil {
return err
}
if !strings.HasSuffix(svcURL, "/") {
svcURL += "/"
}
svcURL += "findOne/" + entityName + "s?"
queryString := ""
structValue := reflect.ValueOf(entity).Elem()

for i := 0; i < structType.NumField(); i++ {
structField := structType.Field(i)
fieldTag := structField.Tag
fieldName := structField.Name
queryStringFieldName := strings.ToLower(fieldName)
omitEmpty := false
if fieldTag != "" {
jTag := fieldTag.Get("json")
if jTag != "" {
jTagElts := strings.Split(jTag, ",")
// This takes care of ",omitempty"
if len(jTagElts) > 1 {
queryStringFieldName = jTagElts[0]
for _, jTag2 := range jTagElts {
if jTag2 == "omitempty" {
omitEmpty = true
break
} // if jTag2
} // for / jTagElts
} else {
queryStringFieldName = jTag
}
} // if jTag
} // if fieldTag
fieldValue := structValue.Field(i).Interface()
if omitEmpty && IsZeroValue(fieldValue) {
log.Printf("Skipping field %s: %v - empty", fieldName, fieldValue)
continue
}

if queryString != "" {
queryString += "&"
}

queryString += fmt.Sprintf("%s=%v", queryStringFieldName, fieldValue)
}
url := svcURL + queryString
log.Printf("Trying to find one %s at %s", entityName, url)
return rc.Get(url, entity)
} // func

// GetServiceUrl is a convenience function, which, given the root
// service URL and name of desired service, returns the URL of that service.
func (rc *RestClient) GetServiceUrl(name string) (string, error) {
Expand Down
34 changes: 17 additions & 17 deletions common/defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
func String(i interface{}) string {
j, e := json.Marshal(i)
if e != nil {
return fmt.Sprintf("%#v", i)
return fmt.Sprintf("%+v", i)
}
return string(j)
}
Expand Down Expand Up @@ -92,8 +92,8 @@ type TokenMessage struct {
// }
// part of the response.
type LinkResponse struct {
Href string
Rel string
Href string `json:"href,omitempty"`
Rel string `json:"rel,omitempty"`
}

// Type definitions
Expand All @@ -105,11 +105,11 @@ type ServiceMessage string
// about the host.
type Host struct {
ID uint64 `sql:"AUTO_INCREMENT" json:"id,omitempty"`
Name string `json:"name"`
Ip string `json:"ip"`
RomanaIp string `json:"romana_ip"`
Name string `json:"name,omitempty"`
Ip string `json:"ip,omitempty"`
RomanaIp string `json:"romana_ip,omitempty"`
AgentPort uint64 `json:"agent_port,omitempty"`
Links Links `json:"links" sql:"-"`
Links Links `json:"links,omitempty" sql:"-"`
}

// Message to register with the root service the actual
Expand Down Expand Up @@ -157,7 +157,7 @@ func (p PortRange) String() string {
// 4. If Protocol specified is "icmp", Ports and PortRanges fields should be blank.
// 5. If Protocol specified is not "icmp", Icmptype and IcmpCode should be unspecified.
type Rule struct {
Protocol string `json:"protocol"`
Protocol string `json:"protocol,omitempty"`
Ports []uint `json:"ports,omitempty"`
PortRanges []PortRange `json:"port_ranges,omitempty"`
// IcmpType only applies if Protocol value is ICMP and
Expand Down Expand Up @@ -193,7 +193,7 @@ type Policy struct {
Name string `json:"name"`
// ID is Romana-generated unique (within Romana deployment) ID of this policy,
// to be used in REST requests. It will be ignored when set by user.
ID uint64 `json:"id,omitempty",sql:"AUTO_INCREMENT"`
ID uint64 `json:"id,omitempty" sql:"AUTO_INCREMENT"`
// ExternalID is an optional identifier of this policy in an external system working
// with Romana in this deployment (e.g., Open Stack).
ExternalID string `json:"external_id,omitempty",sql:"not null;unique"`
Expand All @@ -211,7 +211,7 @@ func (p Policy) String() string {

// isValidProto checks if the Protocol specified in Rule is valid.
// The following protocols are recognized:
// - any -- wildcard
// - any -- see Wildcard
// - tcp
// - udp
// - icmp
Expand Down Expand Up @@ -419,14 +419,14 @@ type Datacenter struct {
// We don't need to store this, but calculate and pass around
Prefix uint64 `json:"prefix"`
Cidr string `json:"cidr,omitempty"`
PrefixBits uint `json:"prefix_bits"`
PortBits uint `json:"port_bits"`
TenantBits uint `json:"tenant_bits"`
SegmentBits uint `json:"segment_bits"`
PrefixBits uint `json:"prefix_bits,omitempty"`
PortBits uint `json:"port_bits,omitempty"`
TenantBits uint `json:"tenant_bits,omitempty"`
SegmentBits uint `json:"segment_bits,omitempty"`
// We don't need to store this, but calculate and pass around
EndpointBits uint `json:"endpoint_bits"`
EndpointSpaceBits uint `json:"endpoint_space_bits"`
Name string `json:"name"`
EndpointBits uint `json:"endpoint_bits,omitempty"`
EndpointSpaceBits uint `json:"endpoint_space_bits,omitempty"`
Name string `json:"name,omitempty"`
}

func (dc Datacenter) String() string {
Expand Down
19 changes: 19 additions & 0 deletions common/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"log"
"os"
"reflect"
"strings"
"sync"
)
Expand All @@ -46,6 +47,24 @@ func initEnviron() {
}
}

// IsZeroValue checks whether the provided value is equal to the
// zero value for the type. Zero values would be:
// - 0 for numeric types
// - "" for strings
// - uninitialized struct for a struct
// - zero-size for a slice or a map
func IsZeroValue(val interface{}) bool {
valType := reflect.TypeOf(val)
valKind := valType.Kind()
if valKind == reflect.Slice || valKind == reflect.Map {
valVal := reflect.ValueOf(val)
return valVal.Len() == 0
}
zeroVal := reflect.Zero(valType).Interface()
log.Printf("Zero value of %+v (type %T, kind %s) is %+v", val, val, valKind, zeroVal)
return val == zeroVal
}

// CleanURL is similar to path.Clean() but to work on URLs
func CleanURL(url string) (string, error) {
elements := strings.Split(url, "/")
Expand Down
2 changes: 1 addition & 1 deletion common/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func write500(writer http.ResponseWriter, m Marshaller, err error) {
httpErr := NewError500(err)
// Should never error out - it's a struct we know.
outData, _ := m.Marshal(httpErr)
log.Printf("Made\n\t%#v\n\tfrom\n\t%#v\n\t%s", httpErr, err, string(outData))
log.Printf("Made\n\t%+v\n\tfrom\n\t%+v\n\t%s", httpErr, err, string(outData))
writer.Write(outData)
}

Expand Down
8 changes: 4 additions & 4 deletions common/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (dbStore *DbStore) Find(query url.Values, entities interface{}, single bool
log.Printf("For %s, query string field %s, struct field %s, DB field %s", t, queryStringField, fieldName, dbField)
queryStringFieldToDbField[queryStringField] = dbField
}
log.Printf("%#v", queryStringFieldToDbField)
log.Printf("%+v", queryStringFieldToDbField)
whereMap := make(map[string]interface{})

for k, v := range query {
Expand All @@ -177,7 +177,7 @@ func (dbStore *DbStore) Find(query url.Values, entities interface{}, single bool
whereMap[dbFieldName] = v[0]
}

log.Printf("Querying with %#v - %T", whereMap, entities)
log.Printf("Querying with %+v - %T", whereMap, entities)

db := dbStore.Db.Where(whereMap).Find(entities)
err := GetDbErrors(db)
Expand All @@ -187,14 +187,14 @@ func (dbStore *DbStore) Find(query url.Values, entities interface{}, single bool
rowCount := reflect.ValueOf(entities).Elem().Len()

if rowCount == 0 {
return nil, NewError404(t.String(), fmt.Sprintf("%#v", whereMap))
return nil, NewError404(t.String(), fmt.Sprintf("%+v", whereMap))
}

if single {
if rowCount == 1 {
return reflect.ValueOf(entities).Elem().Index(0).Interface(), nil
} else {
return nil, NewError500(fmt.Sprintf("Multiple results found for %#v", query))
return nil, NewError500(fmt.Sprintf("Multiple results found for %+v", query))
}
}

Expand Down
66 changes: 19 additions & 47 deletions ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package ipam

import (
"errors"
"fmt"
"github.com/romana/core/common"
"github.com/romana/core/tenant"
Expand Down Expand Up @@ -77,35 +76,25 @@ func (ipam *IPAM) allocateIP(input interface{}, ctx common.RestContext) (interfa
// 2. Kubernetes (CNI Plugin)
// https://github.com/romana/kube/blob/master/CNI/romana#L134
// IP=$(curl -s "http://$ROMANA_MASTER_IP:9601/allocateIP?tenantName=${tenant}&segmentName=${segment}&hostName=${node}" | get_json_kv | get_ip)

tenantParam := ""
tenantLookupField := ""

ten := &tenant.Tenant{}
if tenantID := ctx.QueryVariables.Get("tenantID"); tenantID != "" {
// This is how IPAM plugin driver calls us.
tenantParam = tenantID
tenantLookupField = "external_id"
ten.ExternalID = tenantID
} else if tenantName := ctx.QueryVariables.Get("tenantName"); tenantName != "" {
// This is how CNI plugin calls us.
tenantParam = tenantName
tenantLookupField = "name"
ten.Name = tenantName
} else {
return nil, common.NewError400("Either tenantID or tenantName must be specified.")
}

// check for missing/empty required parameters
if tenantParam == "" {
err := errors.New("Missing or empty tenantName/tenantID parameter")
log.Printf("IPAM encountered an error: %v", err)
return nil, err
}
segmentName := ctx.QueryVariables.Get("segmentName")
if segmentName == "" {
err := errors.New("Missing or empty segmentName parameter")
err := common.NewError400("Missing or empty segmentName parameter")
log.Printf("IPAM encountered an error: %v", err)
return nil, err
}
hostName := ctx.QueryVariables.Get("hostName")
if hostName == "" {
err := errors.New("Missing or empty hostName parameter")
err := common.NewError400("Missing or empty hostName parameter")
log.Printf("IPAM encountered an error: %v", err)
return nil, err
}
Expand All @@ -121,48 +110,31 @@ func (ipam *IPAM) allocateIP(input interface{}, ctx common.RestContext) (interfa
log.Printf("IPAM encountered an error: %v", err)
return nil, err
}
// Get host info from topology service
topoUrl, err := client.GetServiceUrl("topology")
if err != nil {
log.Printf("IPAM encountered an error: %v", err)
return nil, err
}

hostsUrl := fmt.Sprintf("%s/findOne/hosts?name=%s", topoUrl, hostName)
host := common.Host{}
err = client.Get(hostsUrl, &host)
host := &common.Host{}
host.Name = hostName
err = client.FindOne(host)
if err != nil {
log.Printf("IPAM encountered an error finding tenants: %v", err)
log.Printf("IPAM encountered an error finding host for name %s %v", hostName, err)
return nil, err
}
endpoint.HostId = fmt.Sprintf("%d", host.ID)
log.Printf("Host name %s has ID %s", hostName, endpoint.HostId)

tenantSvcUrl, err := client.GetServiceUrl("tenant")
if err != nil {
log.Printf("IPAM encountered an error: %v", err)
return nil, err
}

// TODO follow links once tenant service supports it. For now...
tenantsUrl := fmt.Sprintf("%s/findOne/tenants?%s=%s", tenantSvcUrl, tenantLookupField, tenantParam)
ten := tenant.Tenant{}
err = client.Get(tenantsUrl, &ten)
err = client.FindOne(ten)
if err != nil {
log.Printf("IPAM encountered an error finding tenants: %v", err)
log.Printf("IPAM encountered an error finding tenants %+v: %v", ten, err)
return nil, err
}
endpoint.TenantID = fmt.Sprintf("%d", ten.ID)
log.Printf("IPAM: Tenant '%s' has ID %s, original %d", tenantParam, endpoint.TenantID, ten.ID)

segmentsUrl := fmt.Sprintf("%s/findOne/segments?tenant_id=%s&name=%s", tenantSvcUrl, endpoint.TenantID, segmentName)
segment := tenant.Segment{}
err = client.Get(segmentsUrl, &segment)
seg := &tenant.Segment{Name: segmentName, TenantID: ten.ID}
err = client.FindOne(seg)
if err != nil {
log.Printf("IPAM encountered an error finding segments: %v", err)
log.Printf("IPAM encountered an error finding segments: %+v: %v", seg, err)
return nil, err
}
endpoint.SegmentID = fmt.Sprintf("%d", segment.ID)

endpoint.SegmentID = fmt.Sprintf("%d", seg.ID)
log.Printf("Segment name %s has ID %s", segmentName, endpoint.SegmentID)
return ipam.addEndpoint(&endpoint, ctx)
}
Expand Down Expand Up @@ -323,7 +295,7 @@ func (ipam *IPAM) Initialize() error {

dcURL := index.Links.FindByRel("datacenter")
dc := common.Datacenter{}
log.Printf("IPAM received datacenter information from topology service: %#v\n", dc)
log.Printf("IPAM received datacenter information from topology service: %+v\n", dc)
err = client.Get(dcURL, &dc)
if err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (policy *PolicySvc) augmentEndpoint(endpoint *common.Endpoint) error {
}
endpoint.SegmentNetworkID = &segment.Seq
} else if endpoint.SegmentExternalID != "" || endpoint.SegmentName != "" {
segmentsUrl := fmt.Sprintf("%s/findOne/segments?tenant_id=%d&", tenantSvcUrl, *endpoint.TenantNetworkID)
segmentsUrl := fmt.Sprintf("%s/findOne/segments?tenant_id=%d&", tenantSvcUrl, ten.ID)
if endpoint.SegmentExternalID != "" {
segmentsUrl += "external_id=" + endpoint.TenantExternalID + "&"
}
Expand Down Expand Up @@ -223,7 +223,7 @@ func (policy *PolicySvc) distributePolicy(policyDoc *common.Policy) error {
url := fmt.Sprintf("http://%s:%d/policies", host.Ip, host.AgentPort)
log.Printf("Sending policy %s to agent at %s", policyDoc.Name, url)
result := make(map[string]interface{})
err = policy.client.Post(url, policyDoc, result)
err = policy.client.Post(url, policyDoc, &result)
log.Printf("Agent at %s returned %v", host.Ip, result)
if err != nil {
errStr = append(errStr, fmt.Sprintf("Error applying policy %d to host %s: %v. ", policyDoc.ID, host.Ip, err))
Expand Down
Loading

0 comments on commit 408c3c7

Please sign in to comment.