diff options
Diffstat (limited to 'cloudinit')
| -rw-r--r-- | cloudinit/net/dhcp.py | 42 | ||||
| -rw-r--r-- | cloudinit/sources/DataSourceAzure.py | 47 | 
2 files changed, 60 insertions, 29 deletions
| diff --git a/cloudinit/net/dhcp.py b/cloudinit/net/dhcp.py index 12cf5097..bdc5799f 100644 --- a/cloudinit/net/dhcp.py +++ b/cloudinit/net/dhcp.py @@ -40,34 +40,56 @@ class EphemeralDHCPv4(object):      def __init__(self, iface=None):          self.iface = iface          self._ephipv4 = None +        self.lease = None      def __enter__(self): +        """Setup sandboxed dhcp context.""" +        return self.obtain_lease() + +    def __exit__(self, excp_type, excp_value, excp_traceback): +        """Teardown sandboxed dhcp context.""" +        self.clean_network() + +    def clean_network(self): +        """Exit _ephipv4 context to teardown of ip configuration performed.""" +        if self.lease: +            self.lease = None +        if not self._ephipv4: +            return +        self._ephipv4.__exit__(None, None, None) + +    def obtain_lease(self): +        """Perform dhcp discovery in a sandboxed environment if possible. + +        @return: A dict representing dhcp options on the most recent lease +            obtained from the dhclient discovery if run, otherwise an error +            is raised. + +        @raises: NoDHCPLeaseError if no leases could be obtained. +        """ +        if self.lease: +            return self.lease          try:              leases = maybe_perform_dhcp_discovery(self.iface)          except InvalidDHCPLeaseFileError:              raise NoDHCPLeaseError()          if not leases:              raise NoDHCPLeaseError() -        lease = leases[-1] +        self.lease = leases[-1]          LOG.debug("Received dhcp lease on %s for %s/%s", -                  lease['interface'], lease['fixed-address'], -                  lease['subnet-mask']) +                  self.lease['interface'], self.lease['fixed-address'], +                  self.lease['subnet-mask'])          nmap = {'interface': 'interface', 'ip': 'fixed-address',                  'prefix_or_mask': 'subnet-mask',                  'broadcast': 'broadcast-address',                  'router': 'routers'} -        kwargs = dict([(k, lease.get(v)) for k, v in nmap.items()]) +        kwargs = dict([(k, self.lease.get(v)) for k, v in nmap.items()])          if not kwargs['broadcast']:              kwargs['broadcast'] = bcip(kwargs['prefix_or_mask'], kwargs['ip'])          ephipv4 = EphemeralIPv4Network(**kwargs)          ephipv4.__enter__()          self._ephipv4 = ephipv4 -        return lease - -    def __exit__(self, excp_type, excp_value, excp_traceback): -        if not self._ephipv4: -            return -        self._ephipv4.__exit__(excp_type, excp_value, excp_traceback) +        return self.lease  def maybe_perform_dhcp_discovery(nic=None): diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py index 7bdd43d8..5ec6096f 100644 --- a/cloudinit/sources/DataSourceAzure.py +++ b/cloudinit/sources/DataSourceAzure.py @@ -267,7 +267,6 @@ class DataSourceAzure(sources.DataSource):      dsname = 'Azure'      _negotiated = False      _metadata_imds = sources.UNSET -    lease_info = None      def __init__(self, sys_cfg, distro, paths):          sources.DataSource.__init__(self, sys_cfg, distro, paths) @@ -281,6 +280,7 @@ class DataSourceAzure(sources.DataSource):          self._network_config = None          # Regenerate network config new_instance boot and every boot          self.update_events['network'].add(EventType.BOOT) +        self._ephemeral_dhcp_ctx = None      def __str__(self):          root = sources.DataSource.__str__(self) @@ -407,10 +407,9 @@ class DataSourceAzure(sources.DataSource):                  LOG.warning("%s was not mountable", cdev)                  continue -            should_report_ready_after_reprovision = False -            if reprovision or self._should_reprovision(ret): +            perform_reprovision = reprovision or self._should_reprovision(ret) +            if perform_reprovision:                  ret = self._reprovision() -                should_report_ready_after_reprovision = True              imds_md = get_metadata_from_imds(                  self.fallback_interface, retries=3)              (md, userdata_raw, cfg, files) = ret @@ -438,9 +437,16 @@ class DataSourceAzure(sources.DataSource):          crawled_data['metadata']['instance-id'] = util.read_dmi_data(              'system-uuid') -        if should_report_ready_after_reprovision: +        if perform_reprovision:              LOG.info("Reporting ready to Azure after getting ReprovisionData") -            self._report_ready(lease=self.lease_info) +            use_cached_ephemeral = (net.is_up(self.fallback_interface) and +                                    getattr(self, '_ephemeral_dhcp_ctx', None)) +            if use_cached_ephemeral: +                self._report_ready(lease=self._ephemeral_dhcp_ctx.lease) +                self._ephemeral_dhcp_ctx.clean_network()  # Teardown ephemeral +            else: +                with EphemeralDHCPv4() as lease: +                    self._report_ready(lease=lease)          return crawled_data @@ -529,20 +535,23 @@ class DataSourceAzure(sources.DataSource):          while True:              try: -                with EphemeralDHCPv4() as lease: -                    self.lease_info = lease -                    if report_ready: -                        path = REPORTED_READY_MARKER_FILE -                        LOG.info( -                            "Creating a marker file to report ready: %s", path) -                        util.write_file(path, "{pid}: {time}\n".format( -                            pid=os.getpid(), time=time())) -                        self._report_ready(lease=lease) -                        report_ready = False -                    return readurl(url, timeout=1, headers=headers, -                                   exception_cb=exc_cb, infinite=True, -                                   log_req_resp=False).contents +                # Save our EphemeralDHCPv4 context so we avoid repeated dhcp +                self._ephemeral_dhcp_ctx = EphemeralDHCPv4() +                lease = self._ephemeral_dhcp_ctx.obtain_lease() +                if report_ready: +                    path = REPORTED_READY_MARKER_FILE +                    LOG.info( +                        "Creating a marker file to report ready: %s", path) +                    util.write_file(path, "{pid}: {time}\n".format( +                        pid=os.getpid(), time=time())) +                    self._report_ready(lease=lease) +                    report_ready = False +                return readurl(url, timeout=1, headers=headers, +                               exception_cb=exc_cb, infinite=True, +                               log_req_resp=False).contents              except UrlError: +                # Teardown our EphemeralDHCPv4 context on failure as we retry +                self._ephemeral_dhcp_ctx.clean_network()                  pass      def _report_ready(self, lease): | 
