def create_credentials(): """ Create PKI credentials for TLS access to libvirtd. Credentials are not signed by the host CA. This only allows unverified access but removes the need to transfer files between the host and the guest. """ path = FilePath(tempfile.mkdtemp()) try: ca = RootCredential.initialize(path, b"mycluster") NodeCredential.initialize(path, ca, uuid='client') ca_dir = FilePath('/etc/pki/CA') if not ca_dir.exists(): ca_dir.makedirs() path.child(AUTHORITY_CERTIFICATE_FILENAME).copyTo( FilePath('/etc/pki/CA/cacert.pem') ) client_key_dir = FilePath('/etc/pki/libvirt/private') if not client_key_dir.exists(): client_key_dir.makedirs() client_key_dir.chmod(0700) path.child('client.key').copyTo( client_key_dir.child('clientkey.pem') ) path.child('client.crt').copyTo( FilePath('/etc/pki/libvirt/clientcert.pem') ) finally: path.remove()
def test_no_logging_if_permission_denied(self): """ If there is no permission to write to the given directory this does not prevent the script from running. """ options = usage.Options() sys = FakeSysModule(argv=[b"mythingie"]) logs = FilePath(self.mktemp()) logs.makedirs() logs.chmod(0) self.addCleanup(logs.chmod, 0o777) class Script(object): ran = False def main(self, *args, **kwargs): self.ran = True return succeed(None) script = Script() from twisted.test.test_task import _FakeReactor fakeReactor = _FakeReactor() runner = FlockerScriptRunner(script, options, reactor=fakeReactor, sys_module=sys) runner.log_directory = logs try: with attempt_effective_uid('nobody', suppress_errors=True): runner.main() except SystemExit: pass self.assertTrue(script.ran)
def test_twistd(self): """ Should run twistd with the given arguments """ runner = Runner() fake_twistd = FilePath(self.mktemp()) fake_twistd.setContent('#!%s\n' 'import sys, os\n' 'print " ".join(sys.argv[1:])\n' 'print os.environ["FOO"]\n' 'print os.path.abspath(os.curdir)\n' 'sys.stdout.flush()\n' 'sys.stderr.write("error\\n")\n' 'print "stdout"\n' 'sys.exit(4)\n' % sys.executable) fake_twistd.chmod(0777) runner._twistdBin = lambda: fake_twistd.path path = FilePath(self.mktemp()) path.makedirs() d = runner.twistd(['foo', 'bar', 'baz'], env={'FOO': 'foo value'}, path=path.path) def check(result): out, err, code = result self.assertEqual(code, 4) self.assertEqual(out, 'foo bar baz\n' 'foo value\n' '%s\n' 'stdout\n' % path.path) self.assertEqual(err, 'error\n') return d.addCallback(check)
def test_unix_already_listening_cant_delete(self): """ A config with type = "unix" will create an endpoint for a UNIX socket at the given path, and delete it if required. If it can't delete it, it will raise an exception. """ parent_fp = FilePath("/tmp").child(uuid4().hex) parent_fp.makedirs() fp = parent_fp.child(uuid4().hex) # Something is already there fp.setContent(b"") fp.chmod(0o544) parent_fp.chmod(0o544) reactor = SelectReactor() config = { "type": "unix", "path": fp.path } with self.assertRaises(OSError) as e: create_listening_endpoint_from_config(config, self.cbdir, reactor, self.log) self.assertEqual(e.exception.errno, 13) # Permission Denied parent_fp.chmod(0o777) parent_fp.remove()
def test_file(self): """ An existing file has these attributes """ root = FilePath(self.mktemp()) root.setContent('the content') root.chmod(0777) stdout, stderr, code = self.runScript(['inspect'], json.dumps({ 'kind': 'file', 'path': root.path, })) data = json.loads(stdout) self.assertEqual(data['kind'], 'file') self.assertEqual(data['path'], root.path) self.assertEqual(data['exists'], True) self.assertEqual(data['filetype'], 'file') self.assertEqual(data['owner'], pwd.getpwuid(os.geteuid()).pw_name) self.assertEqual(data['group'], grp.getgrgid(os.getegid()).gr_name) self.assertEqual(data['perms'], '0777') root.restat() self.assertEqual(data['ctime'], int(root.statinfo.st_ctime)) self.assertEqual(type(data['ctime']), int) self.assertEqual(data['mtime'], int(root.statinfo.st_mtime)) self.assertEqual(type(data['mtime']), int) self.assertEqual(data['atime'], int(root.statinfo.st_atime)) self.assertEqual(type(data['atime']), int) self.assertEqual(data['sha1'], sha1('the content').hexdigest()) self.assertEqual(data['size'], len('the content'))
def test_directory(self): """ A directory can exist """ root = FilePath(self.mktemp()) root.makedirs() root.chmod(0777) stdout, stderr, code = self.runScript(['inspect'], json.dumps({ 'kind': 'file', 'path': root.path, })) data = json.loads(stdout) self.assertEqual(data['kind'], 'file') self.assertEqual(data['path'], root.path) self.assertEqual(data['exists'], True) self.assertEqual(data['filetype'], 'dir') self.assertEqual(data['owner'], pwd.getpwuid(os.geteuid()).pw_name) self.assertEqual(data['group'], grp.getgrgid(os.getegid()).gr_name) self.assertEqual(data['perms'], '0777') root.restat() self.assertEqual(data['ctime'], int(root.statinfo.st_ctime)) self.assertEqual(type(data['ctime']), int) self.assertEqual(data['mtime'], int(root.statinfo.st_mtime)) self.assertEqual(type(data['mtime']), int) self.assertEqual(data['atime'], int(root.statinfo.st_atime)) self.assertEqual(type(data['atime']), int)
def test_unix_already_listening_cant_delete(self): """ A config with type = "unix" will create an endpoint for a UNIX socket at the given path, and delete it if required. If it can't delete it, it will raise an exception. """ parent_fp = FilePath("/tmp").child(uuid4().hex) parent_fp.makedirs() fp = parent_fp.child(uuid4().hex) # Something is already there fp.setContent(b"") fp.chmod(0o544) parent_fp.chmod(0o544) reactor = SelectReactor() config = {"type": "unix", "path": fp.path} with self.assertRaises(OSError) as e: create_listening_endpoint_from_config(config, self.cbdir, reactor, self.log) self.assertEqual(e.exception.errno, 13) # Permission Denied parent_fp.chmod(0o777) parent_fp.remove()
def wrapper(case, *args, **kwargs): test_file = FilePath(case.mktemp()) test_file.touch() test_file.chmod(0o000) permissions = test_file.getPermissions() test_file.chmod(0o777) if permissions != Permissions(0o000): raise SkipTest("Can't run test on filesystem with broken permissions.") return test_method(case, *args, **kwargs)
def test_config_write_failed(self): """If writing the config fails then CreateConfigurationError is raised.""" path = FilePath(self.mktemp()) path.makedirs() path.chmod(0) self.addCleanup(path.chmod, 0o777) path = path.child(b"config.json") service = VolumeService(path, None, reactor=Clock()) self.assertRaises(CreateConfigurationError, service.startService)
def test_config_write_failed(self): """If writing the config fails then CreateConfigurationError is raised.""" path = FilePath(self.mktemp()) path.makedirs() path.chmod(0) self.addCleanup(path.chmod, 0o777) path = path.child(b"config.json") service = VolumeService(path, None, reactor=Clock()) with attempt_effective_uid('nobody', suppress_errors=True): self.assertRaises(CreateConfigurationError, service.startService)
def test_config_write_failed(self): """If writing the config fails then CreateConfigurationError is raised.""" path = FilePath(self.mktemp()) path.makedirs() path.chmod(0) self.addCleanup(path.chmod, 0o777) path = path.child(b"config.json") service = VolumeService(path, FilesystemStoragePool(FilePath(self.mktemp())), reactor=Clock()) with attempt_effective_uid("nobody", suppress_errors=True): self.assertRaises(CreateConfigurationError, service.startService)
def test_config_makedirs_failed(self): """If creating the config directory fails then CreateConfigurationError is raised.""" path = FilePath(self.mktemp()) path.makedirs() path.chmod(0) self.addCleanup(path.chmod, 0o777) path = path.child(b"dir").child(b"config.json") service = VolumeService(path, None, reactor=Clock()) with attempt_effective_uid('nobody', suppress_errors=True): self.assertRaises(CreateConfigurationError, service.startService)
def test_no_permission(self): """If the config file is not writeable a meaningful response is written. """ path = FilePath(self.mktemp()) path.makedirs() path.chmod(0) self.addCleanup(path.chmod, 0o777) config = path.child(b"out.json") with attempt_effective_uid("nobody", suppress_errors=True): result = run_expecting_error(b"--config", config.path) self.assertEqual(result, b"Writing config file %s failed: Permission denied\n" % (config.path,))
def _large_request_test(self, request_body_size): """ Assert that when a request with a body of of the given size is received its content is written to the directory the ``TahoeLAFSSite`` is configured with. """ tempdir = FilePath(self.mktemp()) tempdir.makedirs() request = self._create_request(tempdir) # So. Bad news. The temporary file for the uploaded content is # unnamed (and this isn't even necessarily a bad thing since it is how # you get automatic on-process-exit cleanup behavior on POSIX). It's # not visible by inspecting the filesystem. It has no name we can # discover. Then how do we verify it is written to the right place? # The question itself is meaningless if we try to be too precise. It # *has* no filesystem location. However, it is still stored *on* some # filesystem. We still want to make sure it is on the filesystem we # specified because otherwise it might be on a filesystem that's too # small or undesirable in some other way. # # I don't know of any way to ask a file descriptor which filesystem # it's on, either, though. It might be the case that the [f]statvfs() # result could be compared somehow to infer the filesystem but # ... it's not clear what the failure modes might be there, across # different filesystems and runtime environments. # # Another approach is to make the temp directory unwriteable and # observe the failure when an attempt is made to create a file there. # This is hardly a lovely solution but at least it's kind of simple. # # It would be nice if it worked consistently cross-platform but on # Windows os.chmod is more or less broken. if platform.isWindows(): request.gotLength(request_body_size) self.assertThat( tempdir.children(), HasLength(1), ) else: tempdir.chmod(0o550) with self.assertRaises(OSError) as ctx: request.gotLength(request_body_size) raise Exception( "OSError not raised, instead tempdir.children() = {}".format( tempdir.children(), ), ) self.assertThat( ctx.exception.errno, Equals(EACCES), )
def test_permissionDenied(self): """ If the a source file is not readable, this is reported on standard error. """ sourcePath = FilePath(self.mktemp()) sourcePath.setContent('') sourcePath.chmod(0) err = StringIO() count = withStderrTo(err, lambda: checkPath(sourcePath.path)) self.assertEquals(count, 1) self.assertEquals( err.getvalue(), "%s: Permission denied\n" % (sourcePath.path,))
def test_permissionDenied(self): """ If the a source file is not readable, this is reported on standard error. """ sourcePath = FilePath(self.mktemp()) sourcePath.setContent('') sourcePath.chmod(0) err = StringIO() count = withStderrTo(err, lambda: checkPath(sourcePath.path)) self.assertEquals(count, 1) self.assertEquals(err.getvalue(), "%s: Permission denied\n" % (sourcePath.path, ))
def test_no_permission(self): """If the config file is not writeable a meaningful response is written. """ path = FilePath(self.mktemp()) path.makedirs() path.chmod(0) self.addCleanup(path.chmod, 0o777) config = path.child(b"out.json") with attempt_effective_uid('nobody', suppress_errors=True): result = run_expecting_error(b"--config", config.path) self.assertEqual(result, b"Writing config file %s failed: Permission denied\n" % (config.path,))
def test_install_dir_normalises_permissions(self): # install_dir() normalises directory permissions to 0755 and file # permissions to 0644. target_dir = FilePath(self.make_dir()) new_dir = FilePath(self.make_dir()) new_dir.chmod(0700) new_image = new_dir.child("image") new_image.touch() new_image.chmod(0600) install_dir(new_dir.path, target_dir.path) self.assertEqual( "rwxr-xr-x", target_dir.getPermissions().shorthand()) self.assertEqual( "rw-r--r--", target_dir.child("image").getPermissions().shorthand())
def test_exit(self): """ ``VolumeScript._create_volume_service`` raises ``SystemExit`` with a non-zero code if ``VolumeService.startService`` raises ``CreateConfigurationError``. """ directory = FilePath(self.mktemp()) directory.makedirs() directory.chmod(0o000) self.addCleanup(directory.chmod, 0o777) config = directory.child("config.yml") stderr = StringIO() reactor = object() options = VolumeOptions() options.parseOptions([b"--config", config.path]) with attempt_effective_uid("nobody", suppress_errors=True): exc = self.assertRaises(SystemExit, VolumeScript._create_volume_service, stderr, reactor, options) self.assertEqual(1, exc.code)
def makeService(config, reactor=reactor): parent = MultiService() basedir = FilePath(os.path.expanduser(config["basedir"])) basedir.makedirs(ignoreExistingDirectory=True) basedir.chmod(0o700) data = Data(basedir.child("config.json")) dns_server = DNSServerFactory(verbose=0) s1 = UDPServer(int(config["dns-port"]), dns.DNSDatagramProtocol(dns_server), interface=config["dns-interface"]) s1.setServiceParent(parent) s2 = TCPServer(int(config["dns-port"]), dns_server, interface=config["dns-interface"]) s2.setServiceParent(parent) s = Server(data, dns_server) s.update_records() certFile = basedir.child("tub.data").path #furlFile = basedir.child("server.furl").path t = Tub(certFile=certFile) t.setOption("keepaliveTimeout", 60) # ping after 60s of idle t.setOption("disconnectTimeout", 5*60) # disconnect/reconnect after 5m #t.setOption("logLocalFailures", True) #t.setOption("logRemoteFailures", True) #t.unsafeTracebacks = True fp = config["foolscap-port"] if not fp.startswith("tcp:"): raise usage.UsageError("I don't know how to handle non-tcp foolscap-port=") port = int(fp.split(":")[1]) assert port > 1 t.listenOn(fp) t.setLocation("tcp:%s:%d" % (config["hostname"], port)) c = Controller(data, s) cf = t.registerReference(c, furlFile=basedir.child("controller.furl").path) furl_prefix = cf[:cf.rfind("/")+1] c.set_furl_prefix(furl_prefix) t.registerNameLookupHandler(c.lookup) t.setServiceParent(parent) return parent
def test_forbiddenResource(self): """ If the file in the filesystem which would satisfy a request cannot be read, L{File.render} sets the HTTP response code to I{FORBIDDEN}. """ base = FilePath(self.mktemp()) base.setContent('') # Make sure we can delete the file later. self.addCleanup(base.chmod, 0700) # Get rid of our own read permission. base.chmod(0) file = static.File(base.path) request = DummyRequest(['']) d = self._render(file, request) def cbRendered(ignored): self.assertEqual(request.responseCode, 403) d.addCallback(cbRendered) return d
def makeService(config, reactor=reactor): parent = MultiService() basedir = FilePath(os.path.expanduser(config["basedir"])) basedir.makedirs(ignoreExistingDirectory=True) basedir.chmod(0o700) data = Data(basedir.child("config.json")) certFile = basedir.child("tub.data").path tub = Tub(certFile=certFile) tub.setOption("keepaliveTimeout", 60) # ping after 60s of idle tub.setOption("disconnectTimeout", 5*60) # disconnect/reconnect after 5m tub.listenOn("tcp:6319:interface=127.0.0.1") tub.setLocation("tcp:127.0.0.1:6319") tub.setServiceParent(parent) acme_path = basedir.asTextMode() acme_key = maybe_key(acme_path) cert_store = FlancerCertificateStore(data, basedir) staging = not config["really"] if staging: print("STAGING mode") le_url = LETSENCRYPT_STAGING_DIRECTORY else: print("REAL CERTIFICATE mode") le_url = LETSENCRYPT_DIRECTORY client_creator = partial(Client.from_url, reactor=reactor, url=le_url, key=acme_key, alg=RS256) r = FlancerResponder(tub, data) issuer = AcmeIssuingService(cert_store, client_creator, reactor, [r]) issuer.setServiceParent(parent) if "dyndns_furl" in data: start_dyndns_canary(tub, data["dyndns_furl"].encode("ascii")) c = Controller(tub, data, issuer) tub.registerReference(c, furlFile=basedir.child("controller.furl").path) #TimerService(5*60.0, f.timerUpdateStats).setServiceParent(parent) return parent
def test_exit(self): """ ``VolumeScript._create_volume_service`` raises ``SystemExit`` with a non-zero code if ``VolumeService.startService`` raises ``CreateConfigurationError``. """ directory = FilePath(self.mktemp()) directory.makedirs() directory.chmod(0o000) self.addCleanup(directory.chmod, 0o777) config = directory.child("config.yml") stderr = StringIO() reactor = object() options = VolumeOptions() options.parseOptions([b"--config", config.path]) with attempt_effective_uid('nobody', suppress_errors=True): exc = self.assertRaises(SystemExit, VolumeScript._create_volume_service, stderr, reactor, options) self.assertEqual(1, exc.code)
def test_details_written(self): """ ``VolumeScript._create_volume_service`` writes details of the error to the given ``stderr`` if ``VolumeService.startService`` raises ``CreateConfigurationError``. """ directory = FilePath(self.mktemp()) directory.makedirs() directory.chmod(0o000) self.addCleanup(directory.chmod, 0o777) config = directory.child("config.yml") stderr = StringIO() reactor = object() options = VolumeOptions() options.parseOptions([b"--config", config.path]) with attempt_effective_uid("nobody", suppress_errors=True): self.assertRaises(SystemExit, VolumeScript._create_volume_service, stderr, reactor, options) self.assertEqual( "Writing config file {} failed: Permission denied\n".format(config.path).encode("ascii"), stderr.getvalue() )
def test_details_written(self): """ ``VolumeScript._create_volume_service`` writes details of the error to the given ``stderr`` if ``VolumeService.startService`` raises ``CreateConfigurationError``. """ directory = FilePath(self.mktemp()) directory.makedirs() directory.chmod(0o000) self.addCleanup(directory.chmod, 0o777) config = directory.child("config.yml") stderr = StringIO() reactor = object() options = VolumeOptions() options.parseOptions([b"--config", config.path]) with attempt_effective_uid('nobody', suppress_errors=True): self.assertRaises(SystemExit, VolumeScript._create_volume_service, stderr, reactor, options) self.assertEqual( "Writing config file {} failed: Permission denied\n".format( config.path).encode("ascii"), stderr.getvalue())