def std_streams_escalation(): Catch(os.remove, "/tmp/porto-tests/root-secret") Catch(os.remove, "/tmp/porto-tests/porto-alice-stdin") f = open("/tmp/porto-tests/root-secret", "w") f.write("0123456789") os.fchmod(f.fileno(), 0600) f.close() AsAlice() f = open("/tmp/porto-tests/porto-alice-stdin", "w+") f.write("123456") f.close() c = porto.Connection() r = c.Create("test") #run under user run_streams(r) AsRoot() c = porto.Connection() r = c.Find("test") #run under root run_streams(r) AsRoot() c.Destroy("test") os.remove("/tmp/porto-tests/root-secret") os.remove("/tmp/porto-tests/porto-alice-stdin")
def binds_escalation(v): c = porto.Connection() AsAlice() c = porto.Connection() r = c.Create("bind_file") r.SetProperty("env", "PYTHONPATH=/porto/src/api/python") r.SetProperty("bind", "{} /porto ro".format(portosrc)) r.SetProperty("root", v.path) r.SetProperty("bind", "/etc/shadow /tmp/shadow ro") r.SetProperty("command", "python /porto/test/test-security.py read_shadow") assert Catch(r.Start) == porto.exceptions.PermissionError r.SetProperty("bind", "/etc/passwd /tmp/passwd rw") r.SetProperty("command", "python /porto/test/test-security.py append_passwd") assert Catch(r.Start) == porto.exceptions.PermissionError r.SetProperty("bind", "/etc/sudoers /tmp/sudoers rw") r.SetProperty("command", "python /porto/test/test-security.py append_sudoers") assert Catch(r.Start) == porto.exceptions.PermissionError r.SetProperty("bind", "/sbin /tmp/lol rw") r.SetProperty("command", "/tmp/lol/hwclock") assert Catch(r.Start) == porto.exceptions.PermissionError r.Destroy() AsRoot() os.mkdir("/tmp/porto-tests/dir1") os.chmod("/tmp/porto-tests/dir1", 0777) os.mkdir("/tmp/porto-tests/mount1") os.chmod("/tmp/porto-tests/mount1", 0555) os.mkdir("/tmp/porto-tests/dir-bob") os.chmod("/tmp/porto-tests/dir-bob", 0700) os.chown("/tmp/porto-tests/dir-bob", bob_uid, bob_gid) AsAlice() f = open("/tmp/porto-tests/dir1/file", "w+") f.write("123456") f.close() c = porto.Connection() r = c.Create("test") r.SetProperty("bind", "/tmp/porto-tests/dir1 /tmp/porto-tests/mount1/mount2 rw") r.SetProperty("command", "dd if=/dev/zero of=/tmp/porto-tests/mount1/mount2/file bs=32 count=1") assert Catch(r.Start) == porto.exceptions.PermissionError r.SetProperty("bind", "/tmp/porto-tests/dir-bob /tmp/porto-tests/mount1/mount2 rw") assert Catch(r.Start) == porto.exceptions.PermissionError c.Destroy("test") AsRoot()
def layer_escalation(v): (alice_uid, alice_gid) = GetUidGidByUsername("porto-alice") c = porto.Connection(timeout=120) SwitchUser("porto-alice", alice_uid, alice_gid) c = porto.Connection() r = c.Create("test") r.SetProperty("root", v.path) r.SetProperty("env", "PYTHONPATH=/porto/src/api/python") r.SetProperty("bind", "{} /porto ro".format(portosrc)) r.SetProperty( "command", "python /porto/test/test-security.py layer_escalation_container") r.Start() r.Wait() assert Catch(open, "/tmp/porto-tests/evil_file", "r") == IOError assert Catch(c.RemoveLayer, "../../../..") == porto.exceptions.InvalidValue assert Catch(c.ImportLayer, "../etc", "/tmp") == porto.exceptions.InvalidValue r.Destroy() SwitchRoot() f = open("/tmp/porto-tests/good_file", "w") f.write("I am a duck") f.close() SwitchUser("porto-alice", alice_uid, alice_gid) c = porto.Connection() r = c.Create("test") r.SetProperty("root", v.path) r.SetProperty("env", "PYTHONPATH=/porto/src/api/python") r.SetProperty( "command", "python /porto/test/test-security.py layer_escalation_volume_container " + v.path) r.SetProperty("stdout_path", "/tmp/stdout") r.SetProperty("stderr_path", "/tmp/stderr") r.SetProperty("bind", "{} /porto ro; {} /portobin ro".format(portosrc, portobin)) r.Start() r.Wait() assert open("/tmp/porto-tests/good_file", "r").read() == "I am a duck" r.Destroy() SwitchRoot()
def layer_escalation(v): c = porto.Connection(timeout=120) AsAlice() c = porto.Connection() r = c.Create("test") r.SetProperty("root", v.path) r.SetProperty("env", "PYTHONPATH=/porto/src/api/python") r.SetProperty("bind", "{} /porto ro".format(portosrc)) r.SetProperty( "command", "python /porto/test/test-security.py layer_escalation_container") r.Start() r.Wait() ExpectEq(Catch(open, "/tmp/porto-tests/evil_file", "r"), IOError) ExpectEq(Catch(c.RemoveLayer, "../../../.."), porto.exceptions.InvalidValue) ExpectEq(Catch(c.ImportLayer, "../etc", "/tmp"), porto.exceptions.InvalidValue) r.Destroy() AsRoot() f = open("/tmp/porto-tests/good_file", "w") f.write("I am a duck") f.close() AsAlice() c = porto.Connection() r = c.Create("test") r.SetProperty("root", v.path) r.SetProperty("env", "PYTHONPATH=/porto/src/api/python") r.SetProperty( "command", "python /porto/test/test-security.py layer_escalation_volume_container " + v.path) r.SetProperty("stdout_path", "/tmp/stdout") r.SetProperty("stderr_path", "/tmp/stderr") r.SetProperty("bind", "{} /porto ro; {} /portobin ro".format(portosrc, portobin)) r.Start() r.Wait() ExpectEq(open("/tmp/porto-tests/good_file", "r").read(), "I am a duck") r.Destroy() AsRoot()
def test_storage(self): AsAlice() c = porto.Connection() v = c.CreateVolume(storage=storage_name, private_value=volume_private) self.assertEqual(v.storage.name, storage_name) self.assertEqual(v.private, volume_private) self.assertEqual(v.private_value, volume_private) self.assertEqual(v["private"], volume_private) self.assertEqual(v.GetProperty("private"), volume_private) self.assertEqual(c.FindStorage(storage_name).name, storage_name) v.Destroy() v = c.CreateVolume(storage=storage_name) self.assertEqual(v.private_value, volume_private) v.Destroy() st = c.FindStorage(storage_name) self.assertEqual(st.private_value, volume_private) st.Export(storage_tarball_path) st.Remove() with self.assertRaises(porto.exceptions.VolumeNotFound): c.FindStorage(storage_name) c.ImportStorage(storage_name, storage_tarball_path, private_value=volume_private) st = c.FindStorage(storage_name) self.assertEqual(st.private_value, volume_private) st.Remove() os.unlink(storage_tarball_path)
def fuzzer_thread(please_stop, iter_count, fail_count): random.seed(time.time() + os.getpid()) conn=porto.Connection(timeout=opts.timeout) fail_cnt = 0 iter_cnt = 0; while True: if iter_cnt % 100 == 0 and please_stop.is_set(): break iter_cnt += 1 try: select_by_weight([ (100, container_action), (10, volume_action), (1, layer_action) ])(conn) except porto.exceptions.SocketTimeout: if please_stop.is_set(): break fail_cnt += 1 except porto.exceptions.PortoException: fail_cnt += 1 with iter_count.get_lock(): iter_count.value += iter_cnt with fail_count.get_lock(): fail_count.value += fail_cnt
def fuzzer_killer(stop, porto_reloads, porto_kills): random.seed(time.time() + os.getpid()) conn = porto.Connection(timeout=10) while not stop.is_set(): target = select_by_weight([ (90, None), (5, True if opts.reload else None), (5, False if opts.kill else None), ]) if target is None: pid = None elif target: pid = get_portod_master_pid() sig = signal.SIGHUP counter = porto_reloads else: pid = get_portod_pid() sig = signal.SIGKILL counter = porto_kills if pid is not None: os.kill(pid, sig) with counter.get_lock(): counter.value += 1 time.sleep(1) if should_stop(): stop.set()
def cleanup_fuzzer(): conn = porto.Connection() containers = conn.List() while len(containers) > 0: try: conn.Destroy(containers[0]) except porto.exceptions.ContainerDoesNotExist: pass containers = conn.List() volumes = conn.ListVolumes() while len(volumes) > 0: conn.UnlinkVolume(volumes[0].path, "/") volumes = conn.ListVolumes() for layer in conn.ListLayers(): if len(layer.name) == LAYERNAME_LIMIT: layer.Remove() if (os.path.ismount(FUZZER_MNT)): subprocess.check_call(["umount", FUZZER_MNT]) if (os.path.exists(FUZZER_MNT)): os.rmdir(FUZZER_MNT)
def Execute(self, pipe): AsAlice() to_spawn = self.ToSpawn pipe.send("ready") ExpectEq(pipe.recv(), "go") self.Conn = porto.Connection() spawn_times = [] self.Cts = [] for i in range(0, to_spawn): (t, ct) = self.Setup("{}-{}"\ .format(self.Name, str(i))) spawn_times += [t] self.Cts += [ct] pipe.send("spawn ready") ExpectEq(pipe.recv(), "destroy") destroy_times = [] for ct in self.Cts: (t, _) = self.Destroy(ct) destroy_times += [t] AsRoot() pipe.send((spawn_times, destroy_times)) pipe.close()
def cleanup_fuzzer(): conn = porto.Connection() for c in our_containers(conn): try: conn.Destroy(c) except porto.exceptions.ContainerDoesNotExist: pass for v in our_volumes(conn): try: conn.UnlinkVolume(v, '***') except porto.exceptions.VolumeNotFound: pass for l in our_layers(conn): conn.RemoveLayer(l) for path, mnt in ParseMountinfo().iteritems(): if path.startswith(FUZZER_MNT + "/"): print "Stale mount: ", path, mnt global test_fails test_fails += 1 if (os.path.ismount(FUZZER_MNT)): subprocess.check_call(["umount", '-l', FUZZER_MNT]) if (os.path.exists(FUZZER_MNT)): os.rmdir(FUZZER_MNT)
def test_connection(self): c = porto.Connection() self.assertFalse(c.Connected()) c.Connect() self.assertTrue(c.Connected()) c.Disconnect() self.assertFalse(c.Connected()) # AUTO CONNECT c.Version() self.assertTrue(c.Connected()) # AUTO RECONNECT ReloadPortod() self.assertTrue(c.Connected()) c.Version() self.assertTrue(c.Connected()) # NO AUTO RECONNECT c.Disconnect() c.SetAutoReconnect(False) with self.assertRaises(porto.exceptions.SocketError): c.Version() self.assertFalse(c.Connected())
def fuzzer_main(tid, iter_num, queue, verbose=False, timeout=180, print_progress=False, active=False, ignore_failure=False): retry = True iter_saved = 0 warns_value = "0" conn_name = "fuzzer%02d[%d]:" % (tid, os.getpid()) print conn_name + " started\n", while retry: try: pids = get_portod_pid() conn = porto.Connection(timeout=timeout) conn.connect() random.seed(time.time() + os.getpid()) fail_cnt = 0 targets.set_verbose(verbose) targets.set_active(active) for i in range(iter_saved, iter_num): iter_saved = i if i > 0 and i % 100 == 0: if print_progress: print "{} completed {} of {}\n".format( conn_name, i, iter_num), check_portod_pid_valid(*pids) check_errors_present(conn, "{} ".format(conn_name)) if verbose: warns_value = check_warns_present(conn, warns_value) fail_cnt += select_by_weight([(100, targets.container_action), (10, targets.volume_action), (1, targets.layer_action)])(conn) retry = False except BaseException as e: if not ignore_failure or type(e) is AssertionError: queue.put(e) sys.exit(1) else: iter_saved += 1 print "{} finished, action performed: {}, invalid: {}\n".format( conn_name, iter_num, fail_cnt), try: check_errors_present(conn, "{} ".format(conn_name)) check_warns_present(conn, "0") except porto.exceptions.SocketError: pass
def ns_escape(v): try: os.remove("/tmp/porto-tests/root-secret") except: pass f = open("/tmp/porto-tests/root-secret","w") f.write("123456") f.close() os.chmod("/tmp/porto-tests/root-secret", 0600) AsAlice() c = porto.Connection() r = c.Create("parent") r.SetProperty("root", v.path) r.SetProperty("env", "PYTHONPATH=/porto/src/api/python") r.SetProperty("bind", "{} /porto ro".format(portosrc)) r.SetProperty("command", "python /porto/test/test-security.py ns_escape_container 2 1") r.SetProperty("porto_namespace", "parent") r = c.Create("parent/child") r.SetProperty("env", "PYTHONPATH=/porto/src/api/python") #FIXME: #porto r.SetProperty("command","cat /porto/test/test-security.py") shows file contents, but #c.SetProperty("parent/child","command", "python /porto/test/test-security.py ns_escape_container 10 0") fails (file not found) r.SetProperty("command", "sleep 10") r.SetProperty("respawn", "true") r.SetProperty("max_respawns", "1") r.SetProperty("root_readonly","true") r.SetProperty("porto_namespace", "parent/child") r.Start() time.sleep(5) assert c.GetProperty("parent","state") == "dead" and c.GetProperty("parent/child", "state") == "dead" output = c.Get(["parent","parent/child"], ["stdout"]) assert output["parent"]["stdout"] == "OK" #And now vice versa... c.Stop("parent") c.SetProperty("parent", "command", "python /porto/test/test-security.py ns_escape_container 3 0") #Actually, on fail because of ns escape #we won't even find our python test, but anyway... r.SetProperty("command", "python /porto/test/test-security.py ns_escape_container 0 1") r.Start() c.Wait(["parent"]) output = c.Get(["parent","parent/child"], ["stdout"]) assert output["parent"]["stdout"] == "OK\n" assert output["parent/child"]["stdout"] == "OKOK" AsRoot() c.Destroy("parent") os.unlink("/tmp/porto-tests/root-secret")
def TestVolumeRecovery(): print "Make sure porto removes leftover volumes" if os.getpid() != 0: AsRoot() c = porto.Connection(timeout=30) try: shutil.rmtree("/tmp/volume_c") except OSError: pass os.mkdir("/tmp/volume_c", 0755) ExpectEq(len(c.ListVolumes()), 0) limited = c.CreateVolume("/tmp/volume_c", space_limit="100m", inode_limit="1000") unlimited = c.CreateVolume() try: shutil.rmtree("/place/porto_volumes/leftover_volume") except OSError: pass os.mkdir("/place/porto_volumes/leftover_volume", 0755) KillPid(GetPortodPid(), signal.SIGKILL) c.connect() ExpectEq(len(c.ListVolumes()), 2) Expect(not os.path.exists("/place/porto_volumes/leftover_volume")) print "Make sure porto preserves mounted loop/overlayfs" ExpectEq(len(c.ListVolumes()), 2) mounts = [ mount.split()[4] for mount in open("/proc/self/mountinfo", "r").readlines() ] Expect(limited.path in mounts) Expect(unlimited.path in mounts) limited.Unlink() unlimited.Unlink() mounts = [ mount.split()[4] for mount in open("/proc/self/mountinfo", "r").readlines() ] Expect(not limited.path in mounts) Expect(not unlimited.path in mounts) os.rmdir("/tmp/volume_c")
def TestVolumeRecovery(): print "Make sure porto removes leftover volumes" if os.getpid() != 0: SwitchRoot() c = porto.Connection(timeout=30) try: shutil.rmtree("/tmp/volume_c") except OSError: pass os.mkdir("/tmp/volume_c", 0755) assert len(c.ListVolumes()) == 0 limited = c.CreateVolume("/tmp/volume_c", space_limit="100m", inode_limit="1000") unlimited = c.CreateVolume() try: shutil.rmtree("/place/porto_volumes/leftover_volume") except OSError: pass os.mkdir("/place/porto_volumes/leftover_volume", 0755) KillPid(GetSlavePid(), signal.SIGKILL) c.connect() time.sleep(0.5) assert not os.path.exists("/place/porto_volumes/leftover_volume") print "Make sure porto preserves mounted loop/overlayfs" assert len(c.ListVolumes()) == 2 mounts = [ mount.split()[4] for mount in open("/proc/self/mountinfo", "r").readlines() ] assert limited.path in mounts assert unlimited.path in mounts limited.Unlink() unlimited.Unlink() mounts = [ mount.split()[4] for mount in open("/proc/self/mountinfo", "r").readlines() ] assert not limited.path in mounts assert not unlimited.path in mounts os.rmdir("/tmp/volume_c")
def test_error_stringification(self): c = porto.Connection() c.Connect() try: c.Find(container_name) except porto.exceptions.ContainerDoesNotExist as e: self.assertEqual( str(e), "ContainerDoesNotExist: container %s not found" % (container_name, ))
def layer_escalation_volume_container(): os.mkdir("layer") f = open("layer/good_file", "w") f.write("pwned") vol_path = sys.argv[2] c = porto.Connection() subprocess.check_call(["/portobin/portoctl", "vcreate", "/layer", "path={}/../../../../tmp/porto-tests".format(vol_path), "layers=/layer"])
def test_pid_and_reconnect(self): AsAlice() c = porto.Connection() c.Connect() c2 = porto.Connection(auto_reconnect=False) c2.Connect() pid = os.fork() if pid: _, status = os.waitpid(pid, 0) self.assertEqual(status, 0) else: c.Version() with self.assertRaises(porto.exceptions.SocketError): c2.Version() os._exit(0) c2.Disconnect() c.Disconnect()
def test_connection_error(self): if os.path.exists(blackhole): os.remove(blackhole) c = porto.Connection(socket_path=blackhole, timeout=1) start = time.time() with self.assertRaises(porto.exceptions.SocketError): c.Connect() self.assertFalse(c.Connected()) self.assertLess(time.time() - start, 0.1)
def TestBody(): if os.getuid() == 0: DropPrivileges() c = porto.Connection(timeout=30) Simple(c, CONTAINER_MEMORY) LargeSimple(c, GAP) Full(c, CONTAINER_MEMORY, GAP) Hierarchical(c, CONTAINER_MEMORY)
def internal_escalation(v): c = porto.Connection(timeout=120) AsAlice() c = porto.Connection() r = c.Create("test_cont1") r.SetProperty("porto_namespace", "") r.SetProperty("virt_mode", "os") r.SetProperty("root", v.path) r.SetProperty("env", "PYTHONPATH=/porto/src/api/python") r.SetProperty("bind", "{} /porto ro".format(portosrc)) r.SetProperty("command", "python /porto/test/test-security.py internal_escalation_container") r.Start() r.Wait() assert c.GetProperty("test_cont2", "user") == "porto-alice" r.Destroy() c.Destroy("test_cont2") AsRoot()
def print_logged_errors(): try: e = int(porto.Connection(timeout=30).GetProperty("/", "porto_stat[errors]")) except: return msgs = grep_portod_tag("ERR", e if e > 0 else 0) if len(msgs) > 0: print "Found {} errors logged by porto:".format(str(e) if e > 0 else "") for m in msgs: print m
def proc_loop(name, volume, ctx, conn=porto.Connection()): while True: r, root = init_instance(conn, name, volume) root.Unlink() r.Destroy() ctx.Cv.acquire() ctx.Counter.value += 1 if ctx.Counter == CT_COUNT - 1: ctx.Cv.notify_all() while ctx.Counter.value > 0: ctx.Cv.wait() ctx.Cv.release()
def test_meta_storage(self): AsAlice() c = porto.Connection() ms = c.CreateMetaStorage(meta_storage_name, space_limit=2**20) v = c.CreateVolume(storage=storage_in_meta, private=volume_private) f = open(v.path + "/file", 'w') f.write("test") f.close() v.Export(tarball_path) v.Destroy() st = c.FindStorage(storage_in_meta) st.Remove() ml = c.ImportLayer(layer_in_meta, tarball_path) self.assertEqual(c.FindLayer(layer_in_meta).name, layer_in_meta) self.assertEqual(ms.FindLayer("layer").name, layer_in_meta) self.assertEqual(len(ms.ListLayers()), 1) with self.assertRaises(porto.exceptions.Busy): ms.Remove() ms.Update() self.assertEqual(ms.space_limit, 2**20) self.assertTrue(0 < ms.space_available < 2**20) self.assertTrue(0 < ms.space_used < 2**20) self.assertEqual(ms.space_used + ms.space_available, ms.space_limit) ms.Resize(space_limit=2**30) self.assertEqual(ms.space_limit, 2**30) v = c.CreateVolume(storage=storage_in_meta, private=volume_private, layers=[ml]) st = ms.FindStorage("storage") self.assertEqual(st.name, storage_in_meta) self.assertEqual(c.FindStorage(storage_in_meta).name, storage_in_meta) self.assertEqual(len(ms.ListStorages()), 1) v.Destroy() ml.Remove() st.Export(storage_tarball_path) st.Remove() self.assertEqual(len(ms.ListStorages()), 0) st.Import(storage_tarball_path) self.assertEqual(len(ms.ListStorages()), 1) st.Remove() ms.Remove()
def test_weak_containers(self): AsAlice() c = porto.Connection() a = c.CreateWeakContainer(container_name) a.SetProperty("command", "sleep 60") a.Start() c.Disconnect() c.Connect() if Catch(c.Find, container_name) != porto.exceptions.ContainerDoesNotExist: Catch(c.Wait, [container_name], 1000) self.assertEqual(Catch(c.Destroy, container_name), porto.exceptions.ContainerDoesNotExist) Catch(c.Destroy, container_name)
def std_streams_escalation(): (alice_uid, alice_gid) = GetUidGidByUsername("porto-alice") (bob_uid, bob_gid) = GetUidGidByUsername("porto-bob") Catch(os.remove, "/tmp/porto-tests/root-secret") Catch(os.remove, "/tmp/porto-tests/porto-alice-stdin") f = open("/tmp/porto-tests/root-secret", "w") f.write("0123456789") os.fchmod(f.fileno(), 0600) f.close() SwitchUser("porto-alice", alice_uid, alice_gid) f = open("/tmp/porto-tests/porto-alice-stdin", "w+") f.write("123456") f.close() c = porto.Connection() r = c.Create("test") #run under user run_streams(r) SwitchRoot() c = porto.Connection() r = c.Find("test") #run under root run_streams(r) SwitchRoot() c.Destroy("test") os.remove("/tmp/porto-tests/root-secret") os.remove("/tmp/porto-tests/porto-alice-stdin")
def test_connection_timeout(self): blackhole_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) blackhole_sock.bind(blackhole) blackhole_sock.listen(1) c = porto.Connection(socket_path=blackhole, timeout=1) start = time.time() with self.assertRaises(porto.exceptions.SocketTimeout): c.Connect() c.Version() self.assertFalse(c.Connected()) self.assertGreater(time.time() - start, 0.9) os.remove(blackhole)
def fuzzer_killer(prob, timeout=180, verbose=False): if prob == 0.0: sys.exit(0) #Exit with an error if portod spawns errors after restore conn_name = "killer[{}]:".format(os.getpid()) random.seed(time.time() + os.getpid()) conn = porto.Connection(timeout=timeout) conn.connect() warns_value = "0" try: while True: if random.random() < prob: conn.disconnect() select_by_weight([(1, functools.partial(os.kill, get_portod_pid()[1], signal.SIGKILL)), (1, functools.partial(os.kill, get_portod_pid()[0], signal.SIGHUP))])() time.sleep(1) print "{} portod killed\n".format(conn_name), conn.connect() check_errors_present(conn, "{} ".format(conn_name)) if verbose: warns_value = check_warns_present(conn, warns_value) else: time.sleep(1) except BaseException as e: print "{} got {}\n".format(conn_name, e), sys.exit(1)
def porto_namespace_escape(v): AsAlice() c = porto.Connection() r = c.Create("test") r.SetProperty("porto_namespace", "test") r.SetProperty("root", v.path) r.SetProperty("env", "PYTHONPATH=/porto/src/api/python") r.SetProperty("bind", "{} /porto ro".format(portosrc)) r.SetProperty("command", \ "python /porto/test/test-security.py porto_namespace_escape_container") r.Start() r.Wait() ExpectEq(r.GetProperty("porto_namespace"), "test") ExpectNe(r.GetData("exit_status"), "0") r.Destroy() AsRoot()
def tearDown(self): AsRoot() c = porto.Connection() if not Catch(c.Find, container_name): c.Destroy(container_name) if not Catch(c.FindVolume, volume_path): c.DestroyVolume(volume_path) if os.access(volume_path, os.F_OK): os.rmdir(volume_path) for v in c.ListVolumes(): if v.GetProperties().get("private") == volume_private: c.DestroyVolume(v.path) if not Catch(c.FindLayer, layer_name): c.RemoveLayer(layer_name) if os.access(tarball_path, os.F_OK): os.unlink(tarball_path) if os.access(storage_tarball_path, os.F_OK): os.unlink(storage_tarball_path) for l in c.ListLayers(): if l.name == layer_in_meta: l.Remove() for st in c.ListStorages(): if st.name == storage_in_meta: st.Remove() for ms in c.ListMetaStorages(): if ms.name == meta_storage_name: ms.Remove() c.Disconnect()