90 lines
2.2 KiB
Go
90 lines
2.2 KiB
Go
package plugin
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"net/http"
|
|
|
|
. "github.com/weaveworks/weave/common"
|
|
)
|
|
|
|
func (d *dockerer) ipamOp(ID string, op string) (*net.IPNet, error) {
|
|
weaveip, err := d.getContainerBridgeIP(WeaveContainer)
|
|
Log.Debugf("IPAM operation %s for %s", op, ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var res *http.Response
|
|
|
|
url := fmt.Sprintf("http://%s:6784/ip/%s", weaveip, ipamID(ID))
|
|
Log.Debugf("Attempting to %s to %s", op, url)
|
|
if op == "POST" {
|
|
res, err = http.Post(url, "", nil)
|
|
} else if op == "GET" {
|
|
res, err = http.Get(url)
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if res.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("received status %d from IPAM", res.StatusCode)
|
|
}
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parseIP(string(body))
|
|
}
|
|
|
|
// returns an IP for the ID given, allocating a fresh one if necessary
|
|
func (d *dockerer) allocateIP(ID string) (*net.IPNet, error) {
|
|
return d.ipamOp(ID, "POST")
|
|
}
|
|
|
|
// returns an IP for the ID given, or nil if one has not been
|
|
// allocated
|
|
func (d *dockerer) lookupIP(ID string) (*net.IPNet, error) {
|
|
return d.ipamOp(ID, "GET")
|
|
}
|
|
|
|
// release an IP which is no longer needed
|
|
func (d *dockerer) releaseIP(ID string) error {
|
|
weaveip, err := d.getContainerBridgeIP(WeaveContainer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req, err := http.NewRequest("DELETE", fmt.Sprintf("http://%s:6784/ip/%s", weaveip, ipamID(ID)), nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cl := &http.Client{}
|
|
res, err := cl.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusNoContent {
|
|
return fmt.Errorf("unexpected HTTP status code from IP release: %d", res.StatusCode)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseIP(body string) (*net.IPNet, error) {
|
|
ip, ipnet, err := net.ParseCIDR(string(body))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ipnet.IP = ip
|
|
return ipnet, nil
|
|
}
|
|
|
|
// If something looking like a container ID is supplied to IPAM, it
|
|
// will try to check that it's running, and return nothing (and empty
|
|
// string) if it's not. So I make sure it doesn't look like a
|
|
// container ID by including non-hex characters.
|
|
func ipamID(ID string) string {
|
|
return "endpoint:" + ID
|
|
}
|