// setAllocatedOrRelease tries to associate the newly allocated // address addr with the container. On failure it makes the best // effort to cleanup and release addr, logging issues along the way. func (p *ProvisionerAPI) setAllocatedOrRelease( addr *state.IPAddress, environ environs.NetworkingEnviron, instId instance.Id, container *state.Machine, subnetId network.Id, macAddress string, ) (err error) { defer func() { if errors.Cause(err) == nil { // Success! return } logger.Warningf( "failed to mark address %q as %q to container %q: %v (releasing and retrying)", addr.String(), state.AddressStateAllocated, container, err, ) // It's as good as unavailable for us, so mark it as // such. err = setAddrState(addr, state.AddressStateUnavailable) if err != nil { logger.Warningf( "cannot set address %q to %q: %v (ignoring and releasing)", addr.String(), state.AddressStateUnavailable, err, ) } err = environ.ReleaseAddress(instId, subnetId, addr.Address(), addr.MACAddress(), "") if err == nil { logger.Infof("address %q released; trying to allocate new", addr.String()) return } logger.Warningf( "failed to release address %q on instance %q and subnet %q: %v (ignoring and retrying)", addr.String(), instId, subnetId, err, ) }() // Any errors returned below will trigger the release/cleanup // steps above. if err = allocateAddrTo(addr, container, macAddress); err != nil { return errors.Trace(err) } if err = setAddrsTo(addr, container); err != nil { return errors.Trace(err) } logger.Infof("assigned address %q to container %q", addr.String(), container) return nil }