- from the driver
Signed-off-by: Alessandro Boch <aboch@docker.com>
| ... | ... |
@@ -61,6 +61,17 @@ There are many networking solutions available to suit a broad range of use-cases |
| 61 | 61 |
if err != nil {
|
| 62 | 62 |
return |
| 63 | 63 |
} |
| 64 |
+ |
|
| 65 |
+ // libentwork client can check the endpoint's operational data via the Info() API |
|
| 66 |
+ epInfo, err := ep.Info() |
|
| 67 |
+ mapData, ok := epInfo[options.PortMap] |
|
| 68 |
+ if ok {
|
|
| 69 |
+ portMapping, ok := mapData.([]netutils.PortBinding) |
|
| 70 |
+ if ok {
|
|
| 71 |
+ fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping)
|
|
| 72 |
+ } |
|
| 73 |
+ } |
|
| 74 |
+ |
|
| 64 | 75 |
``` |
| 65 | 76 |
|
| 66 | 77 |
## Future |
| ... | ... |
@@ -1,7 +1,10 @@ |
| 1 | 1 |
package main |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 5 |
+ |
|
| 4 | 6 |
"github.com/docker/libnetwork" |
| 7 |
+ "github.com/docker/libnetwork/netutils" |
|
| 5 | 8 |
"github.com/docker/libnetwork/pkg/options" |
| 6 | 9 |
) |
| 7 | 10 |
|
| ... | ... |
@@ -46,4 +49,14 @@ func main() {
|
| 46 | 46 |
if err != nil {
|
| 47 | 47 |
return |
| 48 | 48 |
} |
| 49 |
+ |
|
| 50 |
+ // libentwork client can check the endpoint's operational data via the Info() API |
|
| 51 |
+ epInfo, err := ep.Info() |
|
| 52 |
+ mapData, ok := epInfo[options.PortMap] |
|
| 53 |
+ if ok {
|
|
| 54 |
+ portMapping, ok := mapData.([]netutils.PortBinding) |
|
| 55 |
+ if ok {
|
|
| 56 |
+ fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping)
|
|
| 57 |
+ } |
|
| 58 |
+ } |
|
| 49 | 59 |
} |
| ... | ... |
@@ -40,6 +40,9 @@ type Driver interface {
|
| 40 | 40 |
// passing the network id and endpoint id. |
| 41 | 41 |
DeleteEndpoint(nid, eid types.UUID) error |
| 42 | 42 |
|
| 43 |
+ // EndpointInfo retrieves from the driver the operational data related to the specified endpoint |
|
| 44 |
+ EndpointInfo(nid, eid types.UUID) (map[string]interface{}, error)
|
|
| 45 |
+ |
|
| 43 | 46 |
// Join method is invoked when a Sandbox is attached to an endpoint. |
| 44 | 47 |
Join(nid, eid types.UUID, sboxKey string, options map[string]interface{}) error
|
| 45 | 48 |
|
| ... | ... |
@@ -573,6 +573,46 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
| 573 | 573 |
return nil |
| 574 | 574 |
} |
| 575 | 575 |
|
| 576 |
+func (d *driver) EndpointInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
|
| 577 |
+ // Get the network handler and make sure it exists |
|
| 578 |
+ d.Lock() |
|
| 579 |
+ n := d.network |
|
| 580 |
+ d.Unlock() |
|
| 581 |
+ if n == nil {
|
|
| 582 |
+ return nil, driverapi.ErrNoNetwork |
|
| 583 |
+ } |
|
| 584 |
+ |
|
| 585 |
+ // Sanity check |
|
| 586 |
+ n.Lock() |
|
| 587 |
+ if n.id != nid {
|
|
| 588 |
+ n.Unlock() |
|
| 589 |
+ return nil, InvalidNetworkIDError(nid) |
|
| 590 |
+ } |
|
| 591 |
+ n.Unlock() |
|
| 592 |
+ |
|
| 593 |
+ // Check if endpoint id is good and retrieve correspondent endpoint |
|
| 594 |
+ ep, err := n.getEndpoint(eid) |
|
| 595 |
+ if err != nil {
|
|
| 596 |
+ return nil, err |
|
| 597 |
+ } |
|
| 598 |
+ if ep == nil {
|
|
| 599 |
+ return nil, driverapi.ErrNoEndpoint |
|
| 600 |
+ } |
|
| 601 |
+ |
|
| 602 |
+ m := make(map[string]interface{})
|
|
| 603 |
+ |
|
| 604 |
+ if ep.portMapping != nil {
|
|
| 605 |
+ // Return a copy of the operational data |
|
| 606 |
+ pmc := make([]netutils.PortBinding, 0, len(ep.portMapping)) |
|
| 607 |
+ for _, pm := range ep.portMapping {
|
|
| 608 |
+ pmc = append(pmc, pm.GetCopy()) |
|
| 609 |
+ } |
|
| 610 |
+ m[options.PortMap] = pmc |
|
| 611 |
+ } |
|
| 612 |
+ |
|
| 613 |
+ return m, nil |
|
| 614 |
+} |
|
| 615 |
+ |
|
| 576 | 616 |
// Join method is invoked when a Sandbox is attached to an endpoint. |
| 577 | 617 |
func (d *driver) Join(nid, eid types.UUID, sboxKey string, options map[string]interface{}) error {
|
| 578 | 618 |
var err error |
| ... | ... |
@@ -72,6 +72,68 @@ func TestCreateFullOptions(t *testing.T) {
|
| 72 | 72 |
t.Fatalf("Failed to create bridge: %v", err)
|
| 73 | 73 |
} |
| 74 | 74 |
} |
| 75 |
+ |
|
| 76 |
+func TestQueryEndpointInfo(t *testing.T) {
|
|
| 77 |
+ defer netutils.SetupTestNetNS(t)() |
|
| 78 |
+ |
|
| 79 |
+ _, d := New() |
|
| 80 |
+ |
|
| 81 |
+ config := &Configuration{
|
|
| 82 |
+ BridgeName: DefaultBridgeName, |
|
| 83 |
+ EnableIPTables: true, |
|
| 84 |
+ EnableICC: false, |
|
| 85 |
+ } |
|
| 86 |
+ genericOption := make(map[string]interface{})
|
|
| 87 |
+ genericOption[options.GenericData] = config |
|
| 88 |
+ |
|
| 89 |
+ if err := d.Config(genericOption); err != nil {
|
|
| 90 |
+ t.Fatalf("Failed to setup driver config: %v", err)
|
|
| 91 |
+ } |
|
| 92 |
+ |
|
| 93 |
+ err := d.CreateNetwork("net1", nil)
|
|
| 94 |
+ if err != nil {
|
|
| 95 |
+ t.Fatalf("Failed to create bridge: %v", err)
|
|
| 96 |
+ } |
|
| 97 |
+ |
|
| 98 |
+ portMappings := getPortMapping() |
|
| 99 |
+ epOptions := make(map[string]interface{})
|
|
| 100 |
+ epOptions[options.PortMap] = portMappings |
|
| 101 |
+ |
|
| 102 |
+ _, err = d.CreateEndpoint("net1", "ep1", epOptions)
|
|
| 103 |
+ if err != nil {
|
|
| 104 |
+ t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
|
| 105 |
+ } |
|
| 106 |
+ |
|
| 107 |
+ dd := d.(*driver) |
|
| 108 |
+ ep, _ := dd.network.endpoints["ep1"] |
|
| 109 |
+ data, err := d.EndpointInfo(dd.network.id, ep.id) |
|
| 110 |
+ if err != nil {
|
|
| 111 |
+ t.Fatalf("Failed to ask for endpoint operational data: %v", err)
|
|
| 112 |
+ } |
|
| 113 |
+ pmd, ok := data[options.PortMap] |
|
| 114 |
+ if !ok {
|
|
| 115 |
+ t.Fatalf("Endpoint operational data does not contain port mapping data")
|
|
| 116 |
+ } |
|
| 117 |
+ pm, ok := pmd.([]netutils.PortBinding) |
|
| 118 |
+ if !ok {
|
|
| 119 |
+ t.Fatalf("Unexpected format for port mapping in endpoint operational data")
|
|
| 120 |
+ } |
|
| 121 |
+ if len(ep.portMapping) != len(pm) {
|
|
| 122 |
+ t.Fatalf("Incomplete data for port mapping in endpoint operational data")
|
|
| 123 |
+ } |
|
| 124 |
+ for i, pb := range ep.portMapping {
|
|
| 125 |
+ if !pb.Equal(&pm[i]) {
|
|
| 126 |
+ t.Fatalf("Unexpected data for port mapping in endpoint operational data")
|
|
| 127 |
+ } |
|
| 128 |
+ } |
|
| 129 |
+ |
|
| 130 |
+ // Cleanup as host ports are there |
|
| 131 |
+ err = releasePorts(ep) |
|
| 132 |
+ if err != nil {
|
|
| 133 |
+ t.Fatalf("Failed to release mapped ports: %v", err)
|
|
| 134 |
+ } |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 75 | 137 |
func TestCreateLinkWithOptions(t *testing.T) {
|
| 76 | 138 |
defer netutils.SetupTestNetNS(t)() |
| 77 | 139 |
|
| ... | ... |
@@ -35,6 +35,10 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
| 35 | 35 |
return nil |
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 |
+func (d *driver) EndpointInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
|
| 39 |
+ return make(map[string]interface{}, 0), nil
|
|
| 40 |
+} |
|
| 41 |
+ |
|
| 38 | 42 |
// Join method is invoked when a Sandbox is attached to an endpoint. |
| 39 | 43 |
func (d *driver) Join(nid, eid types.UUID, sboxKey string, options map[string]interface{}) error {
|
| 40 | 44 |
return nil |
| ... | ... |
@@ -34,6 +34,9 @@ type Endpoint interface {
|
| 34 | 34 |
// SandboxInfo returns the sandbox information for this endpoint. |
| 35 | 35 |
SandboxInfo() *sandbox.Info |
| 36 | 36 |
|
| 37 |
+ // Info returns a collection of operational data related to this endpoint retrieved from the driver |
|
| 38 |
+ Info() (map[string]interface{}, error)
|
|
| 39 |
+ |
|
| 37 | 40 |
// Delete and detaches this endpoint from the network. |
| 38 | 41 |
Delete() error |
| 39 | 42 |
} |
| ... | ... |
@@ -94,6 +97,10 @@ func (ep *endpoint) SandboxInfo() *sandbox.Info {
|
| 94 | 94 |
return ep.sandboxInfo.GetCopy() |
| 95 | 95 |
} |
| 96 | 96 |
|
| 97 |
+func (ep *endpoint) Info() (map[string]interface{}, error) {
|
|
| 98 |
+ return ep.network.driver.EndpointInfo(ep.network.id, ep.id) |
|
| 99 |
+} |
|
| 100 |
+ |
|
| 97 | 101 |
func (ep *endpoint) processOptions(options ...EndpointOption) {
|
| 98 | 102 |
for _, opt := range options {
|
| 99 | 103 |
if opt != nil {
|
| ... | ... |
@@ -131,6 +131,22 @@ func TestBridge(t *testing.T) {
|
| 131 | 131 |
t.Fatal(err) |
| 132 | 132 |
} |
| 133 | 133 |
|
| 134 |
+ epInfo, err := ep.Info() |
|
| 135 |
+ if err != nil {
|
|
| 136 |
+ t.Fatal(err) |
|
| 137 |
+ } |
|
| 138 |
+ pmd, ok := epInfo[options.PortMap] |
|
| 139 |
+ if !ok {
|
|
| 140 |
+ t.Fatalf("Could not find expected info in endpoint data")
|
|
| 141 |
+ } |
|
| 142 |
+ pm, ok := pmd.([]netutils.PortBinding) |
|
| 143 |
+ if !ok {
|
|
| 144 |
+ t.Fatalf("Unexpected format for port mapping in endpoint operational data")
|
|
| 145 |
+ } |
|
| 146 |
+ if len(pm) != 3 {
|
|
| 147 |
+ t.Fatalf("Incomplete data for port mapping in endpoint operational data")
|
|
| 148 |
+ } |
|
| 149 |
+ |
|
| 134 | 150 |
if err := ep.Delete(); err != nil {
|
| 135 | 151 |
t.Fatal(err) |
| 136 | 152 |
} |
| ... | ... |
@@ -83,6 +83,43 @@ func (p *PortBinding) GetCopy() PortBinding {
|
| 83 | 83 |
} |
| 84 | 84 |
} |
| 85 | 85 |
|
| 86 |
+// Equal checks if this instance of PortBinding is equal to the passed one |
|
| 87 |
+func (p *PortBinding) Equal(o *PortBinding) bool {
|
|
| 88 |
+ if p == o {
|
|
| 89 |
+ return true |
|
| 90 |
+ } |
|
| 91 |
+ |
|
| 92 |
+ if o == nil {
|
|
| 93 |
+ return false |
|
| 94 |
+ } |
|
| 95 |
+ |
|
| 96 |
+ if p.Proto != o.Proto || p.Port != o.Port || p.HostPort != o.HostPort {
|
|
| 97 |
+ return false |
|
| 98 |
+ } |
|
| 99 |
+ |
|
| 100 |
+ if p.IP != nil {
|
|
| 101 |
+ if !p.IP.Equal(o.IP) {
|
|
| 102 |
+ return false |
|
| 103 |
+ } |
|
| 104 |
+ } else {
|
|
| 105 |
+ if o.IP != nil {
|
|
| 106 |
+ return false |
|
| 107 |
+ } |
|
| 108 |
+ } |
|
| 109 |
+ |
|
| 110 |
+ if p.HostIP != nil {
|
|
| 111 |
+ if !p.HostIP.Equal(o.HostIP) {
|
|
| 112 |
+ return false |
|
| 113 |
+ } |
|
| 114 |
+ } else {
|
|
| 115 |
+ if o.HostIP != nil {
|
|
| 116 |
+ return false |
|
| 117 |
+ } |
|
| 118 |
+ } |
|
| 119 |
+ |
|
| 120 |
+ return true |
|
| 121 |
+} |
|
| 122 |
+ |
|
| 86 | 123 |
const ( |
| 87 | 124 |
// ICMP is for the ICMP ip protocol |
| 88 | 125 |
ICMP = 1 |