Пример #1
0
 def test_ephemeral_ipv4_network_with_prefix(self, m_subp):
     """EphemeralIPv4Network takes a valid prefix to setup the network."""
     params = {
         'interface': 'eth0',
         'ip': '192.168.2.2',
         'prefix_or_mask': '24',
         'broadcast': '192.168.2.255'
     }
     for prefix_val in ['24', 16]:  # prefix can be int or string
         params['prefix_or_mask'] = prefix_val
         with net.EphemeralIPv4Network(**params):
             pass
     m_subp.assert_has_calls([
         mock.call([
             'ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
             'broadcast', '192.168.2.255', 'dev', 'eth0'
         ],
                   capture=True,
                   update_env={'LANG': 'C'})
     ])
     m_subp.assert_has_calls([
         mock.call([
             'ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/16',
             'broadcast', '192.168.2.255', 'dev', 'eth0'
         ],
                   capture=True,
                   update_env={'LANG': 'C'})
     ])
Пример #2
0
    def get_data(self):
        if not on_hetzner():
            return False
        nic = cloudnet.find_fallback_nic()
        with cloudnet.EphemeralIPv4Network(nic, "169.254.0.1", 16,
                                           "169.254.255.255"):
            md = hc_helper.read_metadata(self.metadata_address,
                                         timeout=self.timeout,
                                         sec_between=self.wait_retry,
                                         retries=self.retries)
            ud = hc_helper.read_userdata(self.userdata_address,
                                         timeout=self.timeout,
                                         sec_between=self.wait_retry,
                                         retries=self.retries)

        self.userdata_raw = ud
        self.metadata_full = md
        """hostname is name provided by user at launch.  The API enforces
        it is a valid hostname, but it is not guaranteed to be resolvable
        in dns or fully qualified."""
        self.metadata['instance-id'] = md['instance-id']
        self.metadata['local-hostname'] = md['hostname']
        self.metadata['network-config'] = md.get('network-config', None)
        self.metadata['public-keys'] = md.get('public-keys', None)
        self.vendordata_raw = md.get("vendor_data", None)

        return True
Пример #3
0
    def test_ephemeral_ipv4_network_noop_when_configured(self, m_subp):
        """EphemeralIPv4Network handles exception when address is setup.

        It performs no cleanup as the interface was already setup.
        """
        params = {
            'interface': 'eth0',
            'ip': '192.168.2.2',
            'prefix_or_mask': '255.255.255.0',
            'broadcast': '192.168.2.255'
        }
        m_subp.side_effect = ProcessExecutionError(
            '', 'RTNETLINK answers: File exists', 2)
        expected_calls = [
            mock.call([
                'ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
                'broadcast', '192.168.2.255', 'dev', 'eth0'
            ],
                      capture=True,
                      update_env={'LANG': 'C'})
        ]
        with net.EphemeralIPv4Network(**params):
            pass
        self.assertEqual(expected_calls, m_subp.call_args_list)
        self.assertIn('Skip ephemeral network setup, eth0 already has address',
                      self.logs.getvalue())
Пример #4
0
 def test_ephemeral_ipv4_network_performs_teardown(self, m_subp):
     """EphemeralIPv4Network performs teardown on the device if setup."""
     expected_setup_calls = [
         mock.call([
             'ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
             'broadcast', '192.168.2.255', 'dev', 'eth0'
         ],
                   capture=True,
                   update_env={'LANG': 'C'}),
         mock.call(
             ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'up'],
             capture=True)
     ]
     expected_teardown_calls = [
         mock.call([
             'ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'down'
         ],
                   capture=True),
         mock.call([
             'ip', '-family', 'inet', 'addr', 'del', '192.168.2.2/24',
             'dev', 'eth0'
         ],
                   capture=True)
     ]
     params = {
         'interface': 'eth0',
         'ip': '192.168.2.2',
         'prefix_or_mask': '255.255.255.0',
         'broadcast': '192.168.2.255'
     }
     with net.EphemeralIPv4Network(**params):
         self.assertEqual(expected_setup_calls, m_subp.call_args_list)
     m_subp.assert_has_calls(expected_teardown_calls)
Пример #5
0
    def get_data(self):
        if not on_hetzner():
            return False
        nic = cloudnet.find_fallback_nic()
        with cloudnet.EphemeralIPv4Network(nic, "169.254.0.1", 16,
                                           "169.254.255.255"):
            md = hc_helper.read_metadata(self.metadata_address,
                                         timeout=self.timeout,
                                         sec_between=self.wait_retry,
                                         retries=self.retries)
            ud = hc_helper.read_userdata(self.userdata_address,
                                         timeout=self.timeout,
                                         sec_between=self.wait_retry,
                                         retries=self.retries)

        # Hetzner cloud does not support binary user-data. So here, do a
        # base64 decode of the data if we can. The end result being that a
        # user can provide base64 encoded (possibly gzipped) data as user-data.
        #
        # The fallout is that in the event of b64 encoded user-data,
        # /var/lib/cloud-init/cloud-config.txt will not be identical to the
        # user-data provided.  It will be decoded.
        self.userdata_raw = hc_helper.maybe_b64decode(ud)
        self.metadata_full = md

        # hostname is name provided by user at launch.  The API enforces it is
        # a valid hostname, but it is not guaranteed to be resolvable in dns or
        # fully qualified.
        self.metadata['instance-id'] = md['instance-id']
        self.metadata['local-hostname'] = md['hostname']
        self.metadata['network-config'] = md.get('network-config', None)
        self.metadata['public-keys'] = md.get('public-keys', None)
        self.vendordata_raw = md.get("vendor_data", None)

        return True
Пример #6
0
    def test_ephemeral_ipv4_network_with_new_default_route(self, m_subp):
        """Add the route when router is set and no default route exists."""
        params = {
            'interface': 'eth0',
            'ip': '192.168.2.2',
            'prefix_or_mask': '255.255.255.0',
            'broadcast': '192.168.2.255',
            'router': '192.168.2.1'
        }
        m_subp.return_value = '', ''  # Empty response from ip route gw check
        expected_setup_calls = [
            mock.call([
                'ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
                'broadcast', '192.168.2.255', 'dev', 'eth0'
            ],
                      capture=True,
                      update_env={'LANG': 'C'}),
            mock.call(
                ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'up'],
                capture=True),
            mock.call(['ip', 'route', 'show', '0.0.0.0/0'], capture=True),
            mock.call([
                'ip', '-4', 'route', 'add', 'default', 'via', '192.168.2.1',
                'dev', 'eth0'
            ],
                      capture=True)
        ]
        expected_teardown_calls = [
            mock.call(['ip', '-4', 'route', 'del', 'default', 'dev', 'eth0'],
                      capture=True)
        ]

        with net.EphemeralIPv4Network(**params):
            self.assertEqual(expected_setup_calls, m_subp.call_args_list)
        m_subp.assert_has_calls(expected_teardown_calls)
Пример #7
0
 def test_ephemeral_ipv4_network_with_rfc3442_static_routes(self, m_subp):
     params = {
         'interface':
         'eth0',
         'ip':
         '192.168.2.2',
         'prefix_or_mask':
         '255.255.255.0',
         'broadcast':
         '192.168.2.255',
         'static_routes': [('169.254.169.254/32', '192.168.2.1'),
                           ('0.0.0.0/0', '192.168.2.1')],
         'router':
         '192.168.2.1'
     }
     expected_setup_calls = [
         mock.call([
             'ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
             'broadcast', '192.168.2.255', 'dev', 'eth0'
         ],
                   capture=True,
                   update_env={'LANG': 'C'}),
         mock.call(
             ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'up'],
             capture=True),
         mock.call([
             'ip', '-4', 'route', 'add', '169.254.169.254/32', 'via',
             '192.168.2.1', 'dev', 'eth0'
         ],
                   capture=True),
         mock.call([
             'ip', '-4', 'route', 'add', '0.0.0.0/0', 'via', '192.168.2.1',
             'dev', 'eth0'
         ],
                   capture=True)
     ]
     expected_teardown_calls = [
         mock.call([
             'ip', '-4', 'route', 'del', '0.0.0.0/0', 'via', '192.168.2.1',
             'dev', 'eth0'
         ],
                   capture=True),
         mock.call([
             'ip', '-4', 'route', 'del', '169.254.169.254/32', 'via',
             '192.168.2.1', 'dev', 'eth0'
         ],
                   capture=True),
         mock.call([
             'ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'down'
         ],
                   capture=True),
         mock.call([
             'ip', '-family', 'inet', 'addr', 'del', '192.168.2.2/24',
             'dev', 'eth0'
         ],
                   capture=True)
     ]
     with net.EphemeralIPv4Network(**params):
         self.assertEqual(expected_setup_calls, m_subp.call_args_list)
     m_subp.assert_has_calls(expected_setup_calls + expected_teardown_calls)
Пример #8
0
 def test_ephemeral_ipv4_network_errors_on_missing_params(self, m_subp):
     """No required params for EphemeralIPv4Network can be None."""
     required_params = {
         'interface': 'eth0', 'ip': '192.168.2.2',
         'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255'}
     for key in required_params.keys():
         params = copy.deepcopy(required_params)
         params[key] = None
         with self.assertRaises(ValueError) as context_manager:
             net.EphemeralIPv4Network(**params)
         error = context_manager.exception
         self.assertIn('Cannot init network on', str(error))
         self.assertEqual(0, m_subp.call_count)
Пример #9
0
 def test_ephemeral_ipv4_network_errors_invalid_mask_prefix(self, m_subp):
     """Raise an error when prefix_or_mask is not a netmask or prefix."""
     params = {
         'interface': 'eth0', 'ip': '192.168.2.2',
         'broadcast': '192.168.2.255'}
     invalid_masks = ('invalid', 'invalid.', '123.123.123')
     for error_val in invalid_masks:
         params['prefix_or_mask'] = error_val
         with self.assertRaises(ValueError) as context_manager:
             with net.EphemeralIPv4Network(**params):
                 pass
         error = context_manager.exception
         self.assertIn('Cannot setup network: netmask', str(error))
         self.assertEqual(0, m_subp.call_count)
Пример #10
0
    def _get_data(self):
        (on_hetzner, serial) = get_hcloud_data()

        if not on_hetzner:
            return False

        nic = cloudnet.find_fallback_nic()
        with cloudnet.EphemeralIPv4Network(nic, "169.254.0.1", 16,
                                           "169.254.255.255"):
            md = hc_helper.read_metadata(
                self.metadata_address,
                timeout=self.timeout,
                sec_between=self.wait_retry,
                retries=self.retries,
            )
            ud = hc_helper.read_userdata(
                self.userdata_address,
                timeout=self.timeout,
                sec_between=self.wait_retry,
                retries=self.retries,
            )

        # Hetzner cloud does not support binary user-data. So here, do a
        # base64 decode of the data if we can. The end result being that a
        # user can provide base64 encoded (possibly gzipped) data as user-data.
        #
        # The fallout is that in the event of b64 encoded user-data,
        # /var/lib/cloud-init/cloud-config.txt will not be identical to the
        # user-data provided.  It will be decoded.
        self.userdata_raw = hc_helper.maybe_b64decode(ud)
        self.metadata_full = md

        # hostname is name provided by user at launch.  The API enforces it is
        # a valid hostname, but it is not guaranteed to be resolvable in dns or
        # fully qualified.
        self.metadata["instance-id"] = md["instance-id"]
        self.metadata["local-hostname"] = md["hostname"]
        self.metadata["network-config"] = md.get("network-config", None)
        self.metadata["public-keys"] = md.get("public-keys", None)
        self.vendordata_raw = md.get("vendor_data", None)

        # instance-id and serial from SMBIOS should be identical
        if self.get_instance_id() != serial:
            raise RuntimeError(
                "SMBIOS serial does not match instance ID from metadata")

        return True
Пример #11
0
    def test_ephemeral_ipv4_no_network_if_url_connectivity(
            self, m_readurl, m_subp):
        """No network setup is performed if we can successfully connect to
        connectivity_url."""
        params = {
            'interface': 'eth0',
            'ip': '192.168.2.2',
            'prefix_or_mask': '255.255.255.0',
            'broadcast': '192.168.2.255',
            'connectivity_url': 'http://example.org/index.html'
        }

        with net.EphemeralIPv4Network(**params):
            self.assertEqual(
                [mock.call('http://example.org/index.html', timeout=5)],
                m_readurl.call_args_list)
        # Ensure that no teardown happens:
        m_subp.assert_has_calls([])
Пример #12
0
    def _get_data(self):
        seed_ret = {}
        if util.read_optional_seed(seed_ret, base=(self.seed_dir + "/")):
            self.userdata_raw = seed_ret['user-data']
            self.metadata = seed_ret['meta-data']
            LOG.debug("Using seeded ec2 data from %s", self.seed_dir)
            self._cloud_platform = Platforms.SEEDED
            return True

        strict_mode, _sleep = read_strict_mode(
            util.get_cfg_by_path(self.sys_cfg, STRICT_ID_PATH,
                                 STRICT_ID_DEFAULT), ("warn", None))

        LOG.debug("strict_mode: %s, cloud_platform=%s", strict_mode,
                  self.cloud_platform)
        if strict_mode == "true" and self.cloud_platform == Platforms.UNKNOWN:
            return False
        elif self.cloud_platform == Platforms.NO_EC2_METADATA:
            return False

        if self.get_network_metadata:  # Setup networking in init-local stage.
            if util.is_FreeBSD():
                LOG.debug("FreeBSD doesn't support running dhclient with -sf")
                return False
            dhcp_leases = dhcp.maybe_perform_dhcp_discovery(
                self.fallback_interface)
            if not dhcp_leases:
                # DataSourceEc2Local failed in init-local stage. DataSourceEc2
                # will still run in init-network stage.
                return False
            dhcp_opts = dhcp_leases[-1]
            net_params = {
                'interface': dhcp_opts.get('interface'),
                'ip': dhcp_opts.get('fixed-address'),
                'prefix_or_mask': dhcp_opts.get('subnet-mask'),
                'broadcast': dhcp_opts.get('broadcast-address'),
                'router': dhcp_opts.get('routers')
            }
            with net.EphemeralIPv4Network(**net_params):
                return util.log_time(logfunc=LOG.debug,
                                     msg='Crawl of metadata service',
                                     func=self._crawl_metadata)
        else:
            return self._crawl_metadata()