github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/containernetworking.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "fmt" 8 "net" 9 "strings" 10 11 "github.com/juju/errors" 12 13 "github.com/juju/juju/environs" 14 "github.com/juju/juju/environs/config" 15 "github.com/juju/juju/environs/context" 16 ) 17 18 // AutoConfigureContainerNetworking tries to set up best container networking available 19 // for the specific model if user hasn't set anything. 20 func (m *Model) AutoConfigureContainerNetworking(environ environs.BootstrapEnviron) error { 21 updateAttrs := make(map[string]interface{}) 22 modelConfig, err := m.ModelConfig() 23 if err != nil { 24 return err 25 } 26 fanConfigured, err := m.discoverFan(environ, modelConfig, updateAttrs) 27 if err != nil { 28 return err 29 } 30 31 if modelConfig.ContainerNetworkingMethod() != "" { 32 // Do nothing, user has decided what to do 33 } else if environs.SupportsContainerAddresses(context.CallContext(m.st), environ) { 34 updateAttrs["container-networking-method"] = "provider" 35 } else if fanConfigured { 36 updateAttrs["container-networking-method"] = "fan" 37 } else { 38 updateAttrs["container-networking-method"] = "local" 39 } 40 err = m.UpdateModelConfig(updateAttrs, nil) 41 return err 42 } 43 44 func (m *Model) discoverFan(environ environs.BootstrapEnviron, modelConfig *config.Config, updateAttrs map[string]interface{}) (bool, error) { 45 netEnviron, ok := environs.SupportsNetworking(environ) 46 if !ok { 47 // Not a networking environ, nothing to do here 48 return false, nil 49 } 50 fanConfig, err := modelConfig.FanConfig() 51 if err != nil { 52 return false, err 53 } 54 if len(fanConfig) != 0 { 55 logger.Debugf("Not trying to autoconfigure FAN - configured already") 56 return false, nil 57 } 58 subnets, err := netEnviron.SuperSubnets(context.CallContext(m.st)) 59 if errors.IsNotSupported(err) || (err == nil && len(subnets) == 0) { 60 logger.Debugf("Not trying to autoconfigure FAN - SuperSubnets not supported or empty") 61 return false, nil 62 } 63 if err != nil { 64 return false, err 65 } 66 var outputTable []string 67 68 fanOverlays := []string{"252.0.0.0/8", "253.0.0.0/8", "254.0.0.0/8", "250.0.0.0/8", "251.0.0.0/8"} 69 fanOverlayForUnderlay := func(underlay string) string { 70 _, ipNet, err := net.ParseCIDR(underlay) 71 if err != nil { 72 return "" 73 } 74 // We don't create FAN networks for IPv6 networks 75 if ipNet.IP.To4() == nil { 76 return "" 77 } 78 if ones, _ := ipNet.Mask.Size(); ones <= 8 { 79 return "" 80 } 81 if len(fanOverlays) == 0 { 82 return "" 83 } 84 var overlay string 85 overlay, fanOverlays = fanOverlays[0], fanOverlays[1:] 86 return overlay 87 } 88 for _, subnet := range subnets { 89 overlay := fanOverlayForUnderlay(subnet) 90 if overlay != "" { 91 outputTable = append(outputTable, fmt.Sprintf("%s=%s", subnet, overlay)) 92 } 93 } 94 if len(outputTable) > 0 { 95 updateAttrs["fan-config"] = strings.Join(outputTable, " ") 96 return true, nil 97 } 98 return false, nil 99 }