diff --git a/libnetwork/controller.go b/libnetwork/controller.go index 351e0acccc..914287a5be 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -49,6 +49,7 @@ import ( "net" "strings" "sync" + "time" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" @@ -640,6 +641,7 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... generic: map[string]interface{}{netlabel.GenericData: make(map[string]string)}, ipamType: ipamapi.DefaultIPAM, id: id, + created: time.Now(), ctrlr: c, persist: true, drvOnce: &sync.Once{}, diff --git a/libnetwork/libnetwork_internal_test.go b/libnetwork/libnetwork_internal_test.go index 8bb4881cc6..8adee2a4d8 100644 --- a/libnetwork/libnetwork_internal_test.go +++ b/libnetwork/libnetwork_internal_test.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "testing" + "time" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/discoverapi" @@ -114,6 +115,7 @@ func TestNetworkMarshalling(t *testing.T) { "color": "blue", "superimposed": "", }, + created: time.Now(), } b, err := json.Marshal(n) @@ -133,7 +135,8 @@ func TestNetworkMarshalling(t *testing.T) { !compareIpamInfoList(n.ipamV4Info, nn.ipamV4Info) || !compareIpamConfList(n.ipamV6Config, nn.ipamV6Config) || !compareIpamInfoList(n.ipamV6Info, nn.ipamV6Info) || !compareStringMaps(n.ipamOptions, nn.ipamOptions) || - !compareStringMaps(n.labels, nn.labels) { + !compareStringMaps(n.labels, nn.labels) || + !n.created.Equal(nn.created) { t.Fatalf("JSON marsh/unmarsh failed."+ "\nOriginal:\n%#v\nDecoded:\n%#v"+ "\nOriginal ipamV4Conf: %#v\n\nDecoded ipamV4Conf: %#v"+ diff --git a/libnetwork/network.go b/libnetwork/network.go index 4901c91bc7..8a068d22e9 100644 --- a/libnetwork/network.go +++ b/libnetwork/network.go @@ -6,6 +6,7 @@ import ( "net" "strings" "sync" + "time" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/stringid" @@ -65,6 +66,7 @@ type NetworkInfo interface { Internal() bool Labels() map[string]string Dynamic() bool + Created() time.Time } // EndpointWalker is a client provided function which will be used to walk the Endpoints. @@ -166,6 +168,7 @@ type network struct { name string networkType string id string + created time.Time scope string labels map[string]string ipamType string @@ -208,6 +211,13 @@ func (n *network) ID() string { return n.id } +func (n *network) Created() time.Time { + n.Lock() + defer n.Unlock() + + return n.created +} + func (n *network) Type() string { n.Lock() defer n.Unlock() @@ -320,6 +330,7 @@ func (n *network) CopyTo(o datastore.KVObject) error { dstN := o.(*network) dstN.name = n.name dstN.id = n.id + dstN.created = n.created dstN.networkType = n.networkType dstN.scope = n.scope dstN.dynamic = n.dynamic @@ -397,6 +408,7 @@ func (n *network) MarshalJSON() ([]byte, error) { netMap := make(map[string]interface{}) netMap["name"] = n.name netMap["id"] = n.id + netMap["created"] = n.created netMap["networkType"] = n.networkType netMap["scope"] = n.scope netMap["labels"] = n.labels @@ -451,6 +463,14 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { } n.name = netMap["name"].(string) n.id = netMap["id"].(string) + // "created" is not available in older versions + if v, ok := netMap["created"]; ok { + // n.created is time.Time but marshalled as string + if err = n.created.UnmarshalText([]byte(v.(string))); err != nil { + log.Warnf("failed to unmarshal creation time %v: %v", v, err) + n.created = time.Time{} + } + } n.networkType = netMap["networkType"].(string) n.enableIPv6 = netMap["enableIPv6"].(bool)