def set_up_options_conf(overwrite=True, **kwargs): """Write out the named.conf.options.inside.maas file. This file should be included by the top-level named.conf.options inside its 'options' block. MAAS cannot write the options file itself, so relies on either the DNSFixture in the test suite, or the packaging. Both should set that file up appropriately to include our file. """ template_path = os.path.join( locate_config(TEMPLATES_DIR), "named.conf.options.inside.maas.template") template = tempita.Template.from_filename(template_path) # Make sure "upstream_dns" is set at least to None. It's a # special piece of config that can't be obtained in celery # task code and we don't want to require that every call site # has to specify it. If it's not set, the substitution will # fail with the default template that uses this value. kwargs.setdefault("upstream_dns") try: rendered = template.substitute(kwargs) except NameError as error: raise DNSConfigFail(*error.args) target_path = os.path.join( conf.DNS_CONFIG_DIR, MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME) atomic_write(rendered, target_path, overwrite=overwrite, mode=0644)
def set_up_options_conf(overwrite=True, **kwargs): """Write out the named.conf.options.inside.maas file. This file should be included by the top-level named.conf.options inside its 'options' block. MAAS cannot write the options file itself, so relies on either the DNSFixture in the test suite, or the packaging. Both should set that file up appropriately to include our file. """ template_path = os.path.join(locate_config(TEMPLATES_DIR), "named.conf.options.inside.maas.template") template = tempita.Template.from_filename(template_path) # Make sure "upstream_dns" is set at least to None. It's a # special piece of config that can't be obtained in celery # task code and we don't want to require that every call site # has to specify it. If it's not set, the substitution will # fail with the default template that uses this value. kwargs.setdefault("upstream_dns") try: rendered = template.substitute(kwargs) except NameError as error: raise DNSConfigFail(*error.args) target_path = os.path.join(conf.DNS_CONFIG_DIR, MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME) atomic_write(rendered, target_path, overwrite=overwrite, mode=0644)
def inner_write_config(self, overwrite=True, **kwargs): """Write out this DNS config file.""" template = self.get_template() kwargs.update(self.get_context()) rendered = self.render_template(template, **kwargs) atomic_write( rendered, self.target_path, overwrite=overwrite, mode=self.access_permissions)
def test_atomic_write_sets_permissions(self): atomic_file = self.make_file() # Pick an unusual mode that is also likely to fall outside our # umask. We want this mode set, not treated as advice that may # be tightened up by umask later. mode = 0323 atomic_write(factory.getRandomString(), atomic_file, mode=mode) self.assertEqual(mode, stat.S_IMODE(os.stat(atomic_file).st_mode))
def test_atomic_write_does_not_leak_temp_file_when_not_overwriting(self): # If the file is not written because it already exists and # overwriting was disabled, atomic_write does not leak its # temporary file. filename = self.make_file() atomic_write(factory.getRandomString(), filename, overwrite=False) self.assertEqual( [os.path.basename(filename)], os.listdir(os.path.dirname(filename)))
def inner_write_config(self, overwrite=True, **kwargs): """Write out this DNS config file.""" template = self.get_template() kwargs.update(self.get_context()) rendered = self.render_template(template, **kwargs) atomic_write(rendered, self.target_path, overwrite=overwrite, mode=self.access_permissions)
def test_atomic_write_does_not_leak_temp_file_on_failure(self): # If the overwrite fails, atomic_write does not leak its # temporary file. self.patch(os, 'rename', Mock(side_effect=OSError())) filename = self.make_file() with ExpectedException(OSError): atomic_write(factory.getRandomString(), filename) self.assertEqual( [os.path.basename(filename)], os.listdir(os.path.dirname(filename)))
def test_atomic_write_sets_permissions_before_moving_into_place(self): recorded_modes = [] def record_mode(source, dest): """Stub for os.rename: get source file's access mode.""" recorded_modes.append(os.stat(source).st_mode) self.patch(os, 'rename', Mock(side_effect=record_mode)) playground = self.make_dir() atomic_file = os.path.join(playground, factory.make_name('atomic')) mode = 0323 atomic_write(factory.getRandomString(), atomic_file, mode=mode) [recorded_mode] = recorded_modes self.assertEqual(mode, stat.S_IMODE(recorded_mode))
def set_up_named(self, overwrite_config=True): """Setup an environment to run 'named'. - Creates the default configuration for 'named' and sets up rndc. - Copies the 'named' executable inside homedir. AppArmor won't let us run the installed version the way we want. """ # Generate rndc configuration (rndc config and named snippet). # Disable remote administration for init scripts by suppressing the # "controls" statement. rndcconf, namedrndcconf = generate_rndc( port=self.rndc_port, key_name='dnsfixture-rndc-key', include_default_controls=False) # Write main BIND config file. if should_write(self.conf_file, overwrite_config): named_conf = ( self.NAMED_CONF_TEMPLATE.substitute( homedir=self.homedir, port=self.port, log_file=self.log_file, include_in_options=self.include_in_options, extra=namedrndcconf)) atomic_write( GENERATED_HEADER + named_conf, self.conf_file) # Write rndc config file. if should_write(self.rndcconf_file, overwrite_config): atomic_write( GENERATED_HEADER + rndcconf, self.rndcconf_file) # Copy named executable to home dir. This is done to avoid # the limitations imposed by apparmor if the executable # is in /usr/sbin/named. # named's apparmor profile prevents loading of zone and # configuration files from outside of a restricted set, # none of which an ordinary user has write access to. if should_write(self.named_file, overwrite_config): named_path = self.NAMED_PATH assert os.path.exists(named_path), ( "'%s' executable not found. Install the package " "'bind9' or define an environment variable named " "NAMED_PATH with the path where the 'named' " "executable can be found." % named_path) copy(named_path, self.named_file)
def set_up_named(self, overwrite_config=True): """Setup an environment to run 'named'. - Creates the default configuration for 'named' and sets up rndc. - Copies the 'named' executable inside homedir. AppArmor won't let us run the installed version the way we want. """ # Generate rndc configuration (rndc config and named snippet). # Disable remote administration for init scripts by suppressing the # "controls" statement. rndcconf, namedrndcconf = generate_rndc(port=self.rndc_port, key_name='dnsfixture-rndc-key', include_default_controls=False) # Write main BIND config file. if should_write(self.conf_file, overwrite_config): named_conf = (self.NAMED_CONF_TEMPLATE.substitute( homedir=self.homedir, port=self.port, log_file=self.log_file, include_in_options=self.include_in_options, extra=namedrndcconf)) atomic_write(GENERATED_HEADER + named_conf, self.conf_file) # Write rndc config file. if should_write(self.rndcconf_file, overwrite_config): atomic_write(GENERATED_HEADER + rndcconf, self.rndcconf_file) # Copy named executable to home dir. This is done to avoid # the limitations imposed by apparmor if the executable # is in /usr/sbin/named. # named's apparmor profile prevents loading of zone and # configuration files from outside of a restricted set, # none of which an ordinary user has write access to. if should_write(self.named_file, overwrite_config): named_path = self.NAMED_PATH assert os.path.exists(named_path), ( "'%s' executable not found. Install the package " "'bind9' or define an environment variable named " "NAMED_PATH with the path where the 'named' " "executable can be found." % named_path) copy(named_path, self.named_file)
def test_atomic_write_writes_file_if_no_file_present(self): filename = os.path.join(self.make_dir(), factory.getRandomString()) content = factory.getRandomString() atomic_write(content, filename, overwrite=False) self.assertThat(filename, FileContains(content))
def test_atomic_write_does_not_overwrite_file_if_overwrite_false(self): content = factory.getRandomString() random_content = factory.getRandomString() filename = self.make_file(contents=random_content) atomic_write(content, filename, overwrite=False) self.assertThat(filename, FileContains(random_content))
def test_atomic_write_overwrites_dest_file(self): content = factory.getRandomString() filename = self.make_file(contents=factory.getRandomString()) atomic_write(content, filename) self.assertThat(filename, FileContains(content))
def save(cls, config, filename=None): """Save a YAML configuration to `filename`, or to the default file.""" if filename is None: filename = cls.DEFAULT_FILENAME dump = yaml.safe_dump(config) atomic_write(dump, filename)