~juju-qa/ubuntu/xenial/juju/2.0-rc2

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/apiserver/common/networkingcommon/types.go

  • Committer: Nicholas Skaggs
  • Date: 2016-09-30 14:39:30 UTC
  • mfrom: (1.8.1)
  • Revision ID: nicholas.skaggs@canonical.com-20160930143930-vwwhrefh6ftckccy
import upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
package networkingcommon
5
5
 
6
6
import (
7
 
        "encoding/json"
8
7
        "net"
9
 
        "sort"
10
 
        "strings"
11
8
 
12
9
        "github.com/juju/errors"
13
10
        "github.com/juju/utils/set"
14
11
        "gopkg.in/juju/names.v2"
15
12
 
16
13
        "github.com/juju/juju/apiserver/params"
17
 
        "github.com/juju/juju/cloudconfig/instancecfg"
18
14
        "github.com/juju/juju/environs"
19
15
        "github.com/juju/juju/network"
20
16
        providercommon "github.com/juju/juju/provider/common"
152
148
        }
153
149
}
154
150
 
155
 
type byMACThenCIDRThenIndexThenName []params.NetworkConfig
156
 
 
157
 
func (c byMACThenCIDRThenIndexThenName) Len() int {
158
 
        return len(c)
159
 
}
160
 
 
161
 
func (c byMACThenCIDRThenIndexThenName) Swap(i, j int) {
162
 
        orgI, orgJ := c[i], c[j]
163
 
        c[j], c[i] = orgI, orgJ
164
 
}
165
 
 
166
 
func (c byMACThenCIDRThenIndexThenName) Less(i, j int) bool {
167
 
        if c[i].MACAddress == c[j].MACAddress {
168
 
                // Same MACAddress means related interfaces.
169
 
                if c[i].CIDR == "" || c[j].CIDR == "" {
170
 
                        // Empty CIDRs go at the bottom, otherwise order by InterfaceName.
171
 
                        return c[i].CIDR != "" || c[i].InterfaceName < c[j].InterfaceName
172
 
                }
173
 
                if c[i].DeviceIndex == c[j].DeviceIndex {
174
 
                        if c[i].InterfaceName == c[j].InterfaceName {
175
 
                                // Sort addresses of the same interface.
176
 
                                return c[i].CIDR < c[j].CIDR || c[i].Address < c[j].Address
177
 
                        }
178
 
                        // Prefer shorter names (e.g. parents) with equal DeviceIndex.
179
 
                        return c[i].InterfaceName < c[j].InterfaceName
180
 
                }
181
 
                // When both CIDR and DeviceIndex are non-empty, order by DeviceIndex
182
 
                return c[i].DeviceIndex < c[j].DeviceIndex
183
 
        }
184
 
        // Group by MACAddress.
185
 
        return c[i].MACAddress < c[j].MACAddress
186
 
}
187
 
 
188
 
// SortNetworkConfigsByParents returns the given input sorted, such that any
189
 
// child interfaces appear after their parents.
190
 
func SortNetworkConfigsByParents(input []params.NetworkConfig) []params.NetworkConfig {
191
 
        sortedInputCopy := CopyNetworkConfigs(input)
192
 
        sort.Stable(byMACThenCIDRThenIndexThenName(sortedInputCopy))
193
 
        return sortedInputCopy
194
 
}
195
 
 
196
 
type byInterfaceName []params.NetworkConfig
197
 
 
198
 
func (c byInterfaceName) Len() int {
199
 
        return len(c)
200
 
}
201
 
 
202
 
func (c byInterfaceName) Swap(i, j int) {
203
 
        orgI, orgJ := c[i], c[j]
204
 
        c[j], c[i] = orgI, orgJ
205
 
}
206
 
 
207
 
func (c byInterfaceName) Less(i, j int) bool {
208
 
        return c[i].InterfaceName < c[j].InterfaceName
209
 
}
210
 
 
211
 
// SortNetworkConfigsByInterfaceName returns the given input sorted by
212
 
// InterfaceName.
213
 
func SortNetworkConfigsByInterfaceName(input []params.NetworkConfig) []params.NetworkConfig {
214
 
        sortedInputCopy := CopyNetworkConfigs(input)
215
 
        sort.Stable(byInterfaceName(sortedInputCopy))
216
 
        return sortedInputCopy
217
 
}
218
 
 
219
 
// NetworkConfigsToIndentedJSON returns the given input as an indented JSON
220
 
// string.
221
 
func NetworkConfigsToIndentedJSON(input []params.NetworkConfig) (string, error) {
222
 
        jsonBytes, err := json.MarshalIndent(input, "", "  ")
223
 
        if err != nil {
224
 
                return "", err
225
 
        }
226
 
        return string(jsonBytes), nil
227
 
}
228
 
 
229
 
// CopyNetworkConfigs returns a copy of the given input
230
 
func CopyNetworkConfigs(input []params.NetworkConfig) []params.NetworkConfig {
231
 
        return append([]params.NetworkConfig(nil), input...)
232
 
}
233
 
 
234
151
// NetworkConfigFromInterfaceInfo converts a slice of network.InterfaceInfo into
235
152
// the equivalent params.NetworkConfig slice.
236
153
func NetworkConfigFromInterfaceInfo(interfaceInfos []network.InterfaceInfo) []params.NetworkConfig {
583
500
        return config, nil
584
501
}
585
502
 
586
 
// MergeProviderAndObservedNetworkConfigs returns the effective, sorted, network
587
 
// configs after merging providerConfig with observedConfig.
588
 
func MergeProviderAndObservedNetworkConfigs(providerConfigs, observedConfigs []params.NetworkConfig) ([]params.NetworkConfig, error) {
589
 
        providerConfigsByName := make(map[string][]params.NetworkConfig)
590
 
        sortedProviderConfigs := SortNetworkConfigsByParents(providerConfigs)
591
 
        for _, config := range sortedProviderConfigs {
592
 
                name := config.InterfaceName
593
 
                providerConfigsByName[name] = append(providerConfigsByName[name], config)
594
 
        }
595
 
 
596
 
        jsonProviderConfig, err := NetworkConfigsToIndentedJSON(sortedProviderConfigs)
597
 
        if err != nil {
598
 
                return nil, errors.Annotatef(err, "cannot serialize provider config %#v as JSON", sortedProviderConfigs)
599
 
        }
600
 
        logger.Debugf("provider network config of machine:\n%s", jsonProviderConfig)
601
 
 
602
 
        sortedObservedConfigs := SortNetworkConfigsByParents(observedConfigs)
603
 
        jsonObservedConfig, err := NetworkConfigsToIndentedJSON(sortedObservedConfigs)
604
 
        if err != nil {
605
 
                return nil, errors.Annotatef(err, "cannot serialize observed config %#v as JSON", sortedObservedConfigs)
606
 
        }
607
 
        logger.Debugf("observed network config of machine:\n%s", jsonObservedConfig)
608
 
 
609
 
        var mergedConfigs []params.NetworkConfig
610
 
        for _, config := range sortedObservedConfigs {
611
 
                name := config.InterfaceName
612
 
                logger.Tracef("merging observed config for device %q: %+v", name, config)
613
 
                if strings.HasPrefix(name, instancecfg.DefaultBridgePrefix) {
614
 
                        logger.Tracef("found potential juju bridge %q in observed config", name)
615
 
                        unprefixedName := strings.TrimPrefix(name, instancecfg.DefaultBridgePrefix)
616
 
                        underlyingConfigs, underlyingKnownByProvider := providerConfigsByName[unprefixedName]
617
 
                        logger.Tracef("device %q underlying %q has provider config: %+v", name, unprefixedName, underlyingConfigs)
618
 
                        if underlyingKnownByProvider {
619
 
                                // This config is for a bridge created by Juju and not known by
620
 
                                // the provider. The bridge is configured to adopt the address
621
 
                                // allocated to the underlying interface, which is known by the
622
 
                                // provider. However, since the same underlying interface can
623
 
                                // have multiple addresses, we need to match the adopted
624
 
                                // bridgeConfig to the correct address.
625
 
 
626
 
                                var underlyingConfig params.NetworkConfig
627
 
                                for i, underlying := range underlyingConfigs {
628
 
                                        if underlying.Address == config.Address {
629
 
                                                logger.Tracef("replacing undelying config %+v", underlying)
630
 
                                                // Remove what we found before changing it below.
631
 
                                                underlyingConfig = underlying
632
 
                                                underlyingConfigs = append(underlyingConfigs[:i], underlyingConfigs[i+1:]...)
633
 
                                                break
634
 
                                        }
635
 
                                }
636
 
                                logger.Tracef("underlying provider config after update: %+v", underlyingConfigs)
637
 
 
638
 
                                bridgeConfig := config
639
 
                                bridgeConfig.InterfaceType = string(network.BridgeInterface)
640
 
                                bridgeConfig.ConfigType = underlyingConfig.ConfigType
641
 
                                bridgeConfig.VLANTag = underlyingConfig.VLANTag
642
 
                                bridgeConfig.ProviderId = "" // Juju-created bridges never have a ProviderID
643
 
                                bridgeConfig.ProviderSpaceId = underlyingConfig.ProviderSpaceId
644
 
                                bridgeConfig.ProviderVLANId = underlyingConfig.ProviderVLANId
645
 
                                bridgeConfig.ProviderSubnetId = underlyingConfig.ProviderSubnetId
646
 
                                bridgeConfig.ProviderAddressId = underlyingConfig.ProviderAddressId
647
 
                                if underlyingParent := underlyingConfig.ParentInterfaceName; underlyingParent != "" {
648
 
                                        bridgeConfig.ParentInterfaceName = instancecfg.DefaultBridgePrefix + underlyingParent
649
 
                                }
650
 
 
651
 
                                underlyingConfig.ConfigType = string(network.ConfigManual)
652
 
                                underlyingConfig.ParentInterfaceName = name
653
 
                                underlyingConfig.ProviderAddressId = ""
654
 
                                underlyingConfig.CIDR = ""
655
 
                                underlyingConfig.Address = ""
656
 
 
657
 
                                underlyingConfigs = append(underlyingConfigs, underlyingConfig)
658
 
                                providerConfigsByName[unprefixedName] = underlyingConfigs
659
 
                                logger.Tracef("updated provider network config by name: %+v", providerConfigsByName)
660
 
 
661
 
                                mergedConfigs = append(mergedConfigs, bridgeConfig)
662
 
                                continue
663
 
                        }
664
 
                }
665
 
 
666
 
                knownProviderConfigs, knownByProvider := providerConfigsByName[name]
667
 
                if !knownByProvider {
668
 
                        // Not known by the provider and not a Juju-created bridge, so just
669
 
                        // use the observed config for it.
670
 
                        logger.Tracef("device %q not known to provider - adding only observed config: %+v", name, config)
671
 
                        mergedConfigs = append(mergedConfigs, config)
672
 
                        continue
673
 
                }
674
 
                logger.Tracef("device %q has known provider network config: %+v", name, knownProviderConfigs)
675
 
 
676
 
                for _, providerConfig := range knownProviderConfigs {
677
 
                        if providerConfig.Address == config.Address {
678
 
                                logger.Tracef(
679
 
                                        "device %q has observed address %q, index %d, and MTU %q; overriding index %d and MTU %d from provider config",
680
 
                                        name, config.Address, config.DeviceIndex, config.MTU, providerConfig.DeviceIndex, providerConfig.MTU,
681
 
                                )
682
 
                                // Prefer observed device indices and MTU values as more up-to-date.
683
 
                                providerConfig.DeviceIndex = config.DeviceIndex
684
 
                                providerConfig.MTU = config.MTU
685
 
 
686
 
                                mergedConfigs = append(mergedConfigs, providerConfig)
687
 
                                break
688
 
                        }
689
 
                }
690
 
        }
691
 
 
692
 
        sortedMergedConfigs := SortNetworkConfigsByParents(mergedConfigs)
693
 
 
694
 
        jsonMergedConfig, err := NetworkConfigsToIndentedJSON(sortedMergedConfigs)
695
 
        if err != nil {
696
 
                errors.Annotatef(err, "cannot serialize merged config %#v as JSON", sortedMergedConfigs)
697
 
        }
698
 
        logger.Debugf("combined machine network config:\n%s", jsonMergedConfig)
699
 
 
700
 
        return mergedConfigs, nil
 
503
// MergeProviderAndObservedNetworkConfigs returns the effective network configs,
 
504
// using observedConfigs as a base and selectively updating it using the
 
505
// matching providerConfigs for each interface.
 
506
func MergeProviderAndObservedNetworkConfigs(providerConfigs, observedConfigs []params.NetworkConfig) []params.NetworkConfig {
 
507
 
 
508
        providerConfigByName := networkConfigsByName(providerConfigs)
 
509
        logger.Tracef("known provider config by name: %+v", providerConfigByName)
 
510
 
 
511
        providerConfigByAddress := networkConfigsByAddress(providerConfigs)
 
512
        logger.Tracef("known provider config by address: %+v", providerConfigByAddress)
 
513
 
 
514
        var results []params.NetworkConfig
 
515
        for _, observed := range observedConfigs {
 
516
 
 
517
                name, ipAddress := observed.InterfaceName, observed.Address
 
518
                finalConfig := observed
 
519
 
 
520
                providerConfig, known := providerConfigByName[name]
 
521
                if known {
 
522
                        finalConfig = mergeObservedAndProviderInterfaceConfig(finalConfig, providerConfig)
 
523
                        logger.Debugf("updated observed interface config for %q with: %+v", name, providerConfig)
 
524
                }
 
525
 
 
526
                providerConfig, known = providerConfigByAddress[ipAddress]
 
527
                if known {
 
528
                        finalConfig = mergeObservedAndProviderAddressConfig(finalConfig, providerConfig)
 
529
                        logger.Debugf("updated observed address config for %q with: %+v", name, providerConfig)
 
530
                }
 
531
 
 
532
                results = append(results, finalConfig)
 
533
                logger.Debugf("merged config for %q: %+v", name, finalConfig)
 
534
        }
 
535
 
 
536
        return results
 
537
}
 
538
 
 
539
func networkConfigsByName(input []params.NetworkConfig) map[string]params.NetworkConfig {
 
540
        configsByName := make(map[string]params.NetworkConfig, len(input))
 
541
        for _, config := range input {
 
542
                configsByName[config.InterfaceName] = config
 
543
        }
 
544
        return configsByName
 
545
}
 
546
 
 
547
func networkConfigsByAddress(input []params.NetworkConfig) map[string]params.NetworkConfig {
 
548
        configsByAddress := make(map[string]params.NetworkConfig, len(input))
 
549
        for _, config := range input {
 
550
                configsByAddress[config.Address] = config
 
551
        }
 
552
        return configsByAddress
 
553
}
 
554
 
 
555
func mergeObservedAndProviderInterfaceConfig(observedConfig, providerConfig params.NetworkConfig) params.NetworkConfig {
 
556
        finalConfig := observedConfig
 
557
 
 
558
        // The following fields cannot be observed and are only known by the
 
559
        // provider.
 
560
        finalConfig.ProviderId = providerConfig.ProviderId
 
561
        finalConfig.ProviderVLANId = providerConfig.ProviderVLANId
 
562
        finalConfig.ProviderSubnetId = providerConfig.ProviderSubnetId
 
563
 
 
564
        // The following few fields are only updated if their observed values are
 
565
        // empty.
 
566
 
 
567
        if observedConfig.InterfaceType == "" {
 
568
                finalConfig.InterfaceType = providerConfig.InterfaceType
 
569
        }
 
570
 
 
571
        if observedConfig.VLANTag == 0 {
 
572
                finalConfig.VLANTag = providerConfig.VLANTag
 
573
        }
 
574
 
 
575
        if observedConfig.ParentInterfaceName == "" {
 
576
                finalConfig.ParentInterfaceName = providerConfig.ParentInterfaceName
 
577
        }
 
578
 
 
579
        return finalConfig
 
580
}
 
581
 
 
582
func mergeObservedAndProviderAddressConfig(observedConfig, providerConfig params.NetworkConfig) params.NetworkConfig {
 
583
        finalConfig := observedConfig
 
584
 
 
585
        // The following fields cannot be observed and are only known by the
 
586
        // provider.
 
587
        finalConfig.ProviderAddressId = providerConfig.ProviderAddressId
 
588
        finalConfig.ProviderSubnetId = providerConfig.ProviderSubnetId
 
589
        finalConfig.ProviderSpaceId = providerConfig.ProviderSpaceId
 
590
 
 
591
        // The following few fields are only updated if their observed values are
 
592
        // empty.
 
593
 
 
594
        if observedConfig.ProviderVLANId == "" {
 
595
                finalConfig.ProviderVLANId = providerConfig.ProviderVLANId
 
596
        }
 
597
 
 
598
        if observedConfig.VLANTag == 0 {
 
599
                finalConfig.VLANTag = providerConfig.VLANTag
 
600
        }
 
601
 
 
602
        if observedConfig.ConfigType == "" {
 
603
                finalConfig.ConfigType = providerConfig.ConfigType
 
604
        }
 
605
 
 
606
        if observedConfig.CIDR == "" {
 
607
                finalConfig.CIDR = providerConfig.CIDR
 
608
        }
 
609
 
 
610
        if observedConfig.GatewayAddress == "" {
 
611
                finalConfig.GatewayAddress = providerConfig.GatewayAddress
 
612
        }
 
613
 
 
614
        if len(observedConfig.DNSServers) == 0 {
 
615
                finalConfig.DNSServers = providerConfig.DNSServers
 
616
        }
 
617
 
 
618
        if len(observedConfig.DNSSearchDomains) == 0 {
 
619
                finalConfig.DNSSearchDomains = providerConfig.DNSSearchDomains
 
620
        }
 
621
 
 
622
        return finalConfig
701
623
}