2017-02-07 21:33:23 +00:00
|
|
|
package yaml
|
|
|
|
|
|
|
|
import (
|
2017-07-06 14:28:13 +00:00
|
|
|
"errors"
|
2017-02-07 21:33:23 +00:00
|
|
|
"fmt"
|
2017-07-06 14:28:13 +00:00
|
|
|
"sort"
|
|
|
|
"strings"
|
2017-02-07 21:33:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Networks represents a list of service networks in compose file.
|
|
|
|
// It has several representation, hence this specific struct.
|
|
|
|
type Networks struct {
|
|
|
|
Networks []*Network
|
|
|
|
}
|
|
|
|
|
|
|
|
// Network represents a service network in compose file.
|
|
|
|
type Network struct {
|
|
|
|
Name string `yaml:"-"`
|
|
|
|
RealName string `yaml:"-"`
|
|
|
|
Aliases []string `yaml:"aliases,omitempty"`
|
|
|
|
IPv4Address string `yaml:"ipv4_address,omitempty"`
|
|
|
|
IPv6Address string `yaml:"ipv6_address,omitempty"`
|
|
|
|
}
|
|
|
|
|
2017-07-06 14:28:13 +00:00
|
|
|
// Generate a hash string to detect service network config changes
|
|
|
|
func (n *Networks) HashString() string {
|
|
|
|
if n == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
result := []string{}
|
|
|
|
for _, net := range n.Networks {
|
|
|
|
result = append(result, net.HashString())
|
|
|
|
}
|
|
|
|
sort.Strings(result)
|
|
|
|
return strings.Join(result, ",")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a hash string to detect service network config changes
|
|
|
|
func (n *Network) HashString() string {
|
|
|
|
if n == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
result := []string{}
|
|
|
|
result = append(result, n.Name)
|
|
|
|
result = append(result, n.RealName)
|
|
|
|
sort.Strings(n.Aliases)
|
|
|
|
result = append(result, strings.Join(n.Aliases, ","))
|
|
|
|
result = append(result, n.IPv4Address)
|
|
|
|
result = append(result, n.IPv6Address)
|
|
|
|
sort.Strings(result)
|
|
|
|
return strings.Join(result, ",")
|
|
|
|
}
|
|
|
|
|
2017-02-07 21:33:23 +00:00
|
|
|
// MarshalYAML implements the Marshaller interface.
|
2017-07-06 14:28:13 +00:00
|
|
|
func (n Networks) MarshalYAML() (interface{}, error) {
|
2017-02-07 21:33:23 +00:00
|
|
|
m := map[string]*Network{}
|
|
|
|
for _, network := range n.Networks {
|
|
|
|
m[network.Name] = network
|
|
|
|
}
|
2017-07-06 14:28:13 +00:00
|
|
|
return m, nil
|
2017-02-07 21:33:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalYAML implements the Unmarshaller interface.
|
2017-07-06 14:28:13 +00:00
|
|
|
func (n *Networks) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
|
|
var sliceType []interface{}
|
|
|
|
if err := unmarshal(&sliceType); err == nil {
|
2017-02-07 21:33:23 +00:00
|
|
|
n.Networks = []*Network{}
|
2017-07-06 14:28:13 +00:00
|
|
|
for _, network := range sliceType {
|
2017-02-07 21:33:23 +00:00
|
|
|
name, ok := network.(string)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("Cannot unmarshal '%v' to type %T into a string value", name, name)
|
|
|
|
}
|
|
|
|
n.Networks = append(n.Networks, &Network{
|
|
|
|
Name: name,
|
|
|
|
})
|
|
|
|
}
|
2017-07-06 14:28:13 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var mapType map[interface{}]interface{}
|
|
|
|
if err := unmarshal(&mapType); err == nil {
|
2017-02-07 21:33:23 +00:00
|
|
|
n.Networks = []*Network{}
|
2017-07-06 14:28:13 +00:00
|
|
|
for mapKey, mapValue := range mapType {
|
2017-02-07 21:33:23 +00:00
|
|
|
name, ok := mapKey.(string)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("Cannot unmarshal '%v' to type %T into a string value", name, name)
|
|
|
|
}
|
|
|
|
network, err := handleNetwork(name, mapValue)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
n.Networks = append(n.Networks, network)
|
|
|
|
}
|
2017-07-06 14:28:13 +00:00
|
|
|
return nil
|
2017-02-07 21:33:23 +00:00
|
|
|
}
|
2017-07-06 14:28:13 +00:00
|
|
|
|
|
|
|
return errors.New("Failed to unmarshal Networks")
|
2017-02-07 21:33:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func handleNetwork(name string, value interface{}) (*Network, error) {
|
|
|
|
if value == nil {
|
|
|
|
return &Network{
|
|
|
|
Name: name,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
switch v := value.(type) {
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
network := &Network{
|
|
|
|
Name: name,
|
|
|
|
}
|
|
|
|
for mapKey, mapValue := range v {
|
|
|
|
name, ok := mapKey.(string)
|
|
|
|
if !ok {
|
|
|
|
return &Network{}, fmt.Errorf("Cannot unmarshal '%v' to type %T into a string value", name, name)
|
|
|
|
}
|
|
|
|
switch name {
|
|
|
|
case "aliases":
|
|
|
|
aliases, ok := mapValue.([]interface{})
|
|
|
|
if !ok {
|
|
|
|
return &Network{}, fmt.Errorf("Cannot unmarshal '%v' to type %T into a string value", aliases, aliases)
|
|
|
|
}
|
|
|
|
network.Aliases = []string{}
|
|
|
|
for _, alias := range aliases {
|
|
|
|
network.Aliases = append(network.Aliases, alias.(string))
|
|
|
|
}
|
|
|
|
case "ipv4_address":
|
|
|
|
network.IPv4Address = mapValue.(string)
|
|
|
|
case "ipv6_address":
|
|
|
|
network.IPv6Address = mapValue.(string)
|
|
|
|
default:
|
|
|
|
// Ignorer unknown keys ?
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return network, nil
|
|
|
|
default:
|
|
|
|
return &Network{}, fmt.Errorf("Failed to unmarshal Network: %#v", value)
|
|
|
|
}
|
|
|
|
}
|