github.com/camronlevanger/libcompose@v0.4.1-0.20180423130544-6bb86d53fa21/yaml/network.go (about) 1 package yaml 2 3 import ( 4 "errors" 5 "fmt" 6 "sort" 7 "strings" 8 ) 9 10 // Networks represents a list of service networks in compose file. 11 // It has several representation, hence this specific struct. 12 type Networks struct { 13 Networks []*Network 14 } 15 16 // Network represents a service network in compose file. 17 type Network struct { 18 Name string `yaml:"-"` 19 RealName string `yaml:"-"` 20 Aliases []string `yaml:"aliases,omitempty"` 21 IPv4Address string `yaml:"ipv4_address,omitempty"` 22 IPv6Address string `yaml:"ipv6_address,omitempty"` 23 } 24 25 // Generate a hash string to detect service network config changes 26 func (n *Networks) HashString() string { 27 if n == nil { 28 return "" 29 } 30 result := []string{} 31 for _, net := range n.Networks { 32 result = append(result, net.HashString()) 33 } 34 sort.Strings(result) 35 return strings.Join(result, ",") 36 } 37 38 // Generate a hash string to detect service network config changes 39 func (n *Network) HashString() string { 40 if n == nil { 41 return "" 42 } 43 result := []string{} 44 result = append(result, n.Name) 45 result = append(result, n.RealName) 46 sort.Strings(n.Aliases) 47 result = append(result, strings.Join(n.Aliases, ",")) 48 result = append(result, n.IPv4Address) 49 result = append(result, n.IPv6Address) 50 sort.Strings(result) 51 return strings.Join(result, ",") 52 } 53 54 // MarshalYAML implements the Marshaller interface. 55 func (n Networks) MarshalYAML() (interface{}, error) { 56 m := map[string]*Network{} 57 for _, network := range n.Networks { 58 m[network.Name] = network 59 } 60 return m, nil 61 } 62 63 // UnmarshalYAML implements the Unmarshaller interface. 64 func (n *Networks) UnmarshalYAML(unmarshal func(interface{}) error) error { 65 var sliceType []interface{} 66 if err := unmarshal(&sliceType); err == nil { 67 n.Networks = []*Network{} 68 for _, network := range sliceType { 69 name, ok := network.(string) 70 if !ok { 71 return fmt.Errorf("Cannot unmarshal '%v' to type %T into a string value", name, name) 72 } 73 n.Networks = append(n.Networks, &Network{ 74 Name: name, 75 }) 76 } 77 return nil 78 } 79 80 var mapType map[interface{}]interface{} 81 if err := unmarshal(&mapType); err == nil { 82 n.Networks = []*Network{} 83 for mapKey, mapValue := range mapType { 84 name, ok := mapKey.(string) 85 if !ok { 86 return fmt.Errorf("Cannot unmarshal '%v' to type %T into a string value", name, name) 87 } 88 network, err := handleNetwork(name, mapValue) 89 if err != nil { 90 return err 91 } 92 n.Networks = append(n.Networks, network) 93 } 94 return nil 95 } 96 97 return errors.New("Failed to unmarshal Networks") 98 } 99 100 func handleNetwork(name string, value interface{}) (*Network, error) { 101 if value == nil { 102 return &Network{ 103 Name: name, 104 }, nil 105 } 106 switch v := value.(type) { 107 case map[interface{}]interface{}: 108 network := &Network{ 109 Name: name, 110 } 111 for mapKey, mapValue := range v { 112 name, ok := mapKey.(string) 113 if !ok { 114 return &Network{}, fmt.Errorf("Cannot unmarshal '%v' to type %T into a string value", name, name) 115 } 116 switch name { 117 case "aliases": 118 aliases, ok := mapValue.([]interface{}) 119 if !ok { 120 return &Network{}, fmt.Errorf("Cannot unmarshal '%v' to type %T into a string value", aliases, aliases) 121 } 122 network.Aliases = []string{} 123 for _, alias := range aliases { 124 network.Aliases = append(network.Aliases, alias.(string)) 125 } 126 case "ipv4_address": 127 network.IPv4Address = mapValue.(string) 128 case "ipv6_address": 129 network.IPv6Address = mapValue.(string) 130 default: 131 // Ignorer unknown keys ? 132 continue 133 } 134 } 135 return network, nil 136 default: 137 return &Network{}, fmt.Errorf("Failed to unmarshal Network: %#v", value) 138 } 139 }