github.com/beornf/libcompose@v0.4.1-0.20210215180846-a59802c0f07c/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  }