func (*AddressSuite) TestSortAddresses(c *gc.C) { addrs := network.NewAddresses( "127.0.0.1", "localhost", "example.com", "::1", "fc00::1", "fe80::2", "172.16.0.1", "8.8.8.8", ) network.SortAddresses(addrs, false) c.Assert(addrs, jc.DeepEquals, network.NewAddresses( "example.com", "localhost", "127.0.0.1", "172.16.0.1", "8.8.8.8", "::1", "fe80::2", "fc00::1", )) network.SortAddresses(addrs, true) c.Assert(addrs, jc.DeepEquals, network.NewAddresses( "example.com", "localhost", "fe80::2", "::1", "fc00::1", "127.0.0.1", "172.16.0.1", "8.8.8.8", )) }
// setAddresses updates the machine's addresses (either Addresses or // MachineAddresses, depending on the field argument). Changes are // only predicated on the machine not being Dead; concurrent address // changes are ignored. func (m *Machine) setAddresses(addresses []network.Address, field *[]address, fieldName string) error { var addressesToSet []network.Address if !m.IsContainer() { // Check addresses first. We'll only add those addresses // which are not in the IP address collection. ipAddresses, closer := m.st.getCollection(ipaddressesC) defer closer() addressValues := make([]string, len(addresses)) for i, address := range addresses { addressValues[i] = address.Value } ipDocs := []ipaddressDoc{} sel := bson.D{{"value", bson.D{{"$in", addressValues}}}, {"state", AddressStateAllocated}} err := ipAddresses.Find(sel).All(&ipDocs) if err != nil { return err } ipDocValues := set.NewStrings() for _, ipDoc := range ipDocs { ipDocValues.Add(ipDoc.Value) } for _, address := range addresses { if !ipDocValues.Contains(address.Value) { addressesToSet = append(addressesToSet, address) } } } else { // Containers will set all addresses. addressesToSet = make([]network.Address, len(addresses)) copy(addressesToSet, addresses) } // Update addresses now. envConfig, err := m.st.EnvironConfig() if err != nil { return err } network.SortAddresses(addressesToSet, envConfig.PreferIPv6()) stateAddresses := fromNetworkAddresses(addressesToSet) if addressesEqual(addressesToSet, networkAddresses(*field)) { return nil } if err := m.st.runTransaction([]txn.Op{{ C: machinesC, Id: m.doc.DocID, Assert: notDeadDoc, Update: bson.D{{"$set", bson.D{{fieldName, stateAddresses}}}}, }}); err != nil { if err == txn.ErrAborted { return ErrDead } return errors.Trace(err) } *field = stateAddresses return nil }
// addressesEqual compares the addresses of the machine and the instance information. func addressesEqual(a0, a1 []network.Address) bool { if len(a0) != len(a1) { logger.Tracef("address lists have different lengths %d != %d for %v != %v", len(a0), len(a1), a0, a1) return false } ca0 := make([]network.Address, len(a0)) copy(ca0, a0) network.SortAddresses(ca0, true) ca1 := make([]network.Address, len(a1)) copy(ca1, a1) network.SortAddresses(ca1, true) for i := range ca0 { if ca0[i] != ca1[i] { logger.Tracef("address entry at offset %d has a different value for %v != %v", i, ca0, ca1) return false } } return true }
// setAddresses updates the machine's addresses (either Addresses or // MachineAddresses, depending on the field argument). func (m *Machine) setAddresses(addresses []network.Address, field *[]address, fieldName string) error { var changed bool envConfig, err := m.st.EnvironConfig() if err != nil { return err } network.SortAddresses(addresses, envConfig.PreferIPv6()) stateAddresses := instanceAddressesToAddresses(addresses) buildTxn := func(attempt int) ([]txn.Op, error) { changed = false if attempt > 0 { if err := m.Refresh(); err != nil { return nil, err } } if m.doc.Life == Dead { return nil, ErrDead } op := txn.Op{ C: machinesC, Id: m.doc.Id, Assert: append(bson.D{{fieldName, *field}}, notDeadDoc...), } if !addressesEqual(addresses, addressesToInstanceAddresses(*field)) { op.Update = bson.D{{"$set", bson.D{{fieldName, stateAddresses}}}} changed = true } return []txn.Op{op}, nil } switch err := m.st.run(buildTxn); err { case nil: case jujutxn.ErrExcessiveContention: return errors.Annotatef(err, "cannot set %s for machine %s", fieldName, m) default: return err } if !changed { return nil } *field = stateAddresses return nil }
func (*AddressSuite) TestSortAddresses(c *gc.C) { addrs := network.NewAddresses( "127.0.0.1", "::1", "fc00::1", "169.254.1.2", "localhost", "2001:db8::1", "fe80::2", "7.8.8.8", "172.16.0.1", "example.com", "8.8.8.8", ) network.SortAddresses(addrs) c.Assert(addrs, jc.DeepEquals, network.NewAddresses( // Public IPv4 addresses on top. "7.8.8.8", "8.8.8.8", // After that public IPv6 addresses. "2001:db8::1", // Then hostnames. "example.com", "localhost", // Then IPv4 cloud-local addresses. "172.16.0.1", // Then IPv6 cloud-local addresses. "fc00::1", // Then machine-local IPv4 addresses. "127.0.0.1", // Then machine-local IPv6 addresses. "::1", // Then link-local IPv4 addresses. "169.254.1.2", // Finally, link-local IPv6 addresses. "fe80::2", )) }