Skip to content

Commit

Permalink
Allow flexible routing
Browse files Browse the repository at this point in the history
- Provide an easy way to build routing for clients

[#86337946]

Signed-off-by: Matthew Sykes <[email protected]>
  • Loading branch information
atulkc authored and sykesm committed Feb 3, 2015
1 parent 36c7af7 commit b11a7b8
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 35 deletions.
2 changes: 1 addition & 1 deletion cmd/receptor/actual_lrp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var _ = Describe("Actual LRP API", func() {
"instance-guid-"+index,
"cell-id",
)
netInfo := models.NewActualLRPNetInfo("the-host", []models.PortMapping{{ContainerPort: 80, HostPort: uint32(1000 + i)}})
netInfo := models.NewActualLRPNetInfo("the-host", []models.PortMapping{{ContainerPort: 80, HostPort: uint16(1000 + i)}})
err := bbs.StartActualLRP(lrpKey, containerKey, netInfo, logger)
Ω(err).ShouldNot(HaveOccurred())
}
Expand Down
13 changes: 10 additions & 3 deletions cmd/receptor/desired_lrp_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main_test

import (
"encoding/json"
"fmt"
"sync/atomic"

Expand Down Expand Up @@ -82,7 +83,13 @@ var _ = Describe("Desired LRP API", func() {

instances := 6
annotation := "update-annotation"
routes := []string{"updated-route"}
rawMessage := json.RawMessage([]byte(`[{"port":8080,"hostnames":["updated-route"]}]`))
routes := map[string]*json.RawMessage{
"cf-router": &rawMessage,
}
routingInfo := receptor.RoutingInfo{
CFRoutes: []receptor.CFRoute{{Port: 8080, Hostnames: []string{"updated-route"}}},
}

BeforeEach(func() {
createLRPReq := newValidDesiredLRPCreateRequest()
Expand All @@ -92,7 +99,7 @@ var _ = Describe("Desired LRP API", func() {
update := receptor.DesiredLRPUpdateRequest{
Instances: &instances,
Annotation: &annotation,
Routes: routes,
Routes: &routingInfo,
}

updateErr = client.UpdateDesiredLRP(createLRPReq.ProcessGuid, update)
Expand Down Expand Up @@ -199,7 +206,7 @@ func newValidDesiredLRPCreateRequest() receptor.DesiredLRPCreateRequest {
Domain: "test-domain",
Stack: "some-stack",
Instances: 1,
Ports: []uint32{1234, 5678},
Ports: []uint16{1234, 5678},
Action: &models.RunAction{
Path: "/bin/bash",
},
Expand Down
32 changes: 27 additions & 5 deletions cmd/receptor/event_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main_test

import (
"encoding/json"
"time"

"github.com/cloudfoundry-incubator/receptor"
Expand Down Expand Up @@ -40,11 +41,14 @@ var _ = Describe("Event", func() {
}
}()

rawMessage := json.RawMessage([]byte(`{"port":8080,"hosts":["primer-route"]}`))
primerLRP := models.DesiredLRP{
ProcessGuid: "primer-guid",
Domain: "primer-domain",
Stack: "primer-stack",
Routes: []string{"primer-route"},
Routes: map[string]*json.RawMessage{
"router": &rawMessage,
},
Action: &models.RunAction{
Path: "true",
},
Expand All @@ -59,7 +63,12 @@ var _ = Describe("Event", func() {
case <-events:
break PRIMING
case <-time.After(50 * time.Millisecond):
err = bbs.UpdateDesiredLRP(logger, primerLRP.ProcessGuid, models.DesiredLRPUpdate{Routes: []string{"garbage-route"}})
routeMsg := json.RawMessage([]byte(`{"port":8080,"hosts":["garbage-route"]}`))
err = bbs.UpdateDesiredLRP(logger, primerLRP.ProcessGuid, models.DesiredLRPUpdate{
Routes: map[string]*json.RawMessage{
"router": &routeMsg,
},
})
Ω(err).ShouldNot(HaveOccurred())
}
}
Expand All @@ -85,11 +94,15 @@ var _ = Describe("Event", func() {

Describe("Desired LRPs", func() {
BeforeEach(func() {
routeMessage := json.RawMessage([]byte(`[{"port":8080,"hostnames":["original-route"]}]`))
routes := map[string]*json.RawMessage{
receptor.CFRouter: &routeMessage,
}
desiredLRP = models.DesiredLRP{
ProcessGuid: "some-guid",
Domain: "some-domain",
Stack: "some-stack",
Routes: []string{"original-route"},
Routes: routes,
Action: &models.RunAction{
Path: "true",
},
Expand All @@ -109,15 +122,24 @@ var _ = Describe("Event", func() {
Ω(desiredLRPCreatedEvent.DesiredLRPResponse).Should(Equal(serialization.DesiredLRPToResponse(desiredLRP)))

By("updating an existing DesiredLRP")
newRoutes := []string{"new-route"}
routeMessage := json.RawMessage([]byte(`[{"port":8080,"hostnames":["new-route"]}]`))
newRoutes := map[string]*json.RawMessage{
receptor.CFRouter: &routeMessage,
}
expectedRoutingInfo := receptor.RoutingInfo{
CFRoutes: []receptor.CFRoute{{
Port: 8080,
Hostnames: []string{"new-route"},
}},
}
err = bbs.UpdateDesiredLRP(logger, desiredLRP.ProcessGuid, models.DesiredLRPUpdate{Routes: newRoutes})
Ω(err).ShouldNot(HaveOccurred())

Eventually(events).Should(Receive(&event))

desiredLRPChangedEvent, ok := event.(receptor.DesiredLRPChangedEvent)
Ω(ok).Should(BeTrue())
Ω(desiredLRPChangedEvent.After.Routes).Should(Equal(newRoutes))
Ω(desiredLRPChangedEvent.After.Routes).Should(Equal(&expectedRoutingInfo))

By("removing the DesiredLRP")
err = bbs.RemoveDesiredLRPByProcessGuid(logger, desiredLRP.ProcessGuid)
Expand Down
16 changes: 14 additions & 2 deletions handlers/desired_lrp_handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,12 +278,24 @@ var _ = Describe("Desired LRP Handlers", func() {
expectedProcessGuid := "some-guid"
instances := 15
annotation := "new-annotation"
routes := []string{"new-route-1", "new-route-2"}
routingInfo := receptor.RoutingInfo{
CFRoutes: []receptor.CFRoute{
{
Port: 8080,
Hostnames: []string{"new-route-1", "new-route-2"},
},
},
}

routeMessage := json.RawMessage(`[{"port":8080,"hostnames":["new-route-1","new-route-2"]}]`)
routes := map[string]*json.RawMessage{
receptor.CFRouter: &routeMessage,
}

validUpdateRequest := receptor.DesiredLRPUpdateRequest{
Instances: &instances,
Annotation: &annotation,
Routes: routes,
Routes: &routingInfo,
}

expectedUpdate := models.DesiredLRPUpdate{
Expand Down
72 changes: 63 additions & 9 deletions resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ type EnvironmentVariable struct {
}

type PortMapping struct {
ContainerPort uint32 `json:"container_port"`
HostPort uint32 `json:"host_port,omitempty"`
ContainerPort uint16 `json:"container_port"`
HostPort uint16 `json:"host_port,omitempty"`
}

const (
Expand Down Expand Up @@ -154,6 +154,60 @@ func (response *TaskResponse) UnmarshalJSON(payload []byte) error {
return nil
}

const CFRouter = "cf-router"

type CFRoute struct {
Port uint16 `json:"port"`
Hostnames []string `json:"hostnames"`
}

type CFRoutes []CFRoute

type RoutingInfo struct {
CFRoutes
Other map[string]*json.RawMessage
}

func (r RoutingInfo) MarshalJSON() ([]byte, error) {
out := make(map[string]*json.RawMessage)
for k, v := range r.Other {
out[k] = v
}

if len(r.CFRoutes) > 0 {
bytes, err := json.Marshal(r.CFRoutes)
if err != nil {
return nil, err
}
raw := json.RawMessage(bytes)
out[CFRouter] = &raw
}

return json.Marshal(out)
}

func (r *RoutingInfo) UnmarshalJSON(data []byte) error {
var out map[string]*json.RawMessage
err := json.Unmarshal(data, &out)
if err != nil {
return err
}

if cfroutes, ok := out[CFRouter]; ok {
delete(out, CFRouter)
err := json.Unmarshal(*cfroutes, &r.CFRoutes)
if err != nil {
return err
}
}

if len(out) > 0 {
r.Other = out
}

return nil
}

type DesiredLRPCreateRequest struct {
ProcessGuid string `json:"process_guid"`
Domain string `json:"domain"`
Expand All @@ -169,8 +223,8 @@ type DesiredLRPCreateRequest struct {
MemoryMB int `json:"memory_mb"`
CPUWeight uint `json:"cpu_weight"`
Privileged bool `json:"privileged"`
Ports []uint32 `json:"ports"`
Routes []string `json:"routes"`
Ports []uint16 `json:"ports"`
Routes *RoutingInfo `json:"routes,omitempty"`
LogGuid string `json:"log_guid"`
LogSource string `json:"log_source"`
Annotation string `json:"annotation,omitempty"`
Expand Down Expand Up @@ -270,9 +324,9 @@ func (request *DesiredLRPCreateRequest) UnmarshalJSON(payload []byte) error {
}

type DesiredLRPUpdateRequest struct {
Instances *int `json:"instances,omitempty"`
Routes []string `json:"routes,omitempty"`
Annotation *string `json:"annotation,omitempty"`
Instances *int `json:"instances,omitempty"`
Routes *RoutingInfo `json:"routes,omitempty"`
Annotation *string `json:"annotation,omitempty"`
}

type DesiredLRPResponse struct {
Expand All @@ -290,8 +344,8 @@ type DesiredLRPResponse struct {
MemoryMB int `json:"memory_mb"`
CPUWeight uint `json:"cpu_weight"`
Privileged bool `json:"privileged"`
Ports []uint32 `json:"ports"`
Routes []string `json:"routes"`
Ports []uint16 `json:"ports"`
Routes *RoutingInfo `json:"routes,omitempty"`
LogGuid string `json:"log_guid"`
LogSource string `json:"log_source"`
Annotation string `json:"annotation,omitempty"`
Expand Down
42 changes: 42 additions & 0 deletions resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,46 @@ var _ = Describe("Resources", func() {
})
})
})

Describe("RoutingInfo", func() {
var r receptor.RoutingInfo

BeforeEach(func() {
r.Other = make(map[string]*json.RawMessage)
})

Context("Serialization", func() {
jsonRoutes := `{
"cf-router": [{ "port": 1, "hostnames": ["a", "b"]}],
"foo" : "bar"
}`

Context("MarshalJson", func() {
It("marshals routes when present", func() {
r.CFRoutes = append(r.CFRoutes, receptor.CFRoute{Port: 1, Hostnames: []string{"a", "b"}})
msg := json.RawMessage([]byte(`"bar"`))
r.Other["foo"] = &msg
bytes, err := json.Marshal(r)
Ω(err).ShouldNot(HaveOccurred())
Ω(bytes).Should(MatchJSON(jsonRoutes))
})
})

Context("Unmarshal", func() {
It("returns both cf-routes and other", func() {
err := json.Unmarshal([]byte(jsonRoutes), &r)
Ω(err).ShouldNot(HaveOccurred())

Ω(r.CFRoutes).Should(HaveLen(1))
route := r.CFRoutes[0]
Ω(route.Port).Should(Equal(uint16(1)))
Ω(route.Hostnames).Should(ConsistOf("a", "b"))

Ω(r.Other).Should(HaveLen(1))
raw := r.Other["foo"]
Ω([]byte(*raw)).Should(Equal([]byte(`"bar"`)))
})
})
})
})
})
Loading

0 comments on commit b11a7b8

Please sign in to comment.