2022-02-17 13:56:31 +00:00
|
|
|
from contextlib import contextmanager
|
|
|
|
|
2020-04-24 11:48:09 +00:00
|
|
|
from util import remote_fn
|
|
|
|
|
|
|
|
|
|
|
|
def scrub(volume_id):
|
2020-04-24 15:38:18 +00:00
|
|
|
import time
|
2021-11-19 15:29:49 +00:00
|
|
|
from subprocess import CalledProcessError
|
|
|
|
|
2020-04-24 15:38:18 +00:00
|
|
|
import rawfile_util
|
2021-11-19 15:29:49 +00:00
|
|
|
from consts import VOLUME_IN_USE_EXIT_CODE
|
2020-04-24 15:38:18 +00:00
|
|
|
|
2021-06-25 20:48:00 +00:00
|
|
|
img_dir = rawfile_util.img_dir(volume_id)
|
|
|
|
if not img_dir.exists():
|
|
|
|
return
|
|
|
|
|
2021-11-19 15:29:49 +00:00
|
|
|
img_file = rawfile_util.img_file(volume_id)
|
|
|
|
loops = rawfile_util.attached_loops(img_file)
|
|
|
|
if len(loops) > 0:
|
|
|
|
raise CalledProcessError(returncode=VOLUME_IN_USE_EXIT_CODE, cmd="")
|
|
|
|
|
2021-02-26 12:03:14 +00:00
|
|
|
now = time.time()
|
|
|
|
deleted_at = now
|
|
|
|
gc_at = now # TODO: GC sensitive PVCs later
|
|
|
|
rawfile_util.patch_metadata(volume_id, {"deleted_at": deleted_at, "gc_at": gc_at})
|
|
|
|
rawfile_util.gc_if_needed(volume_id, dry_run=False)
|
2020-04-24 11:48:09 +00:00
|
|
|
|
|
|
|
|
2020-11-06 14:44:47 +00:00
|
|
|
def init_rawfile(volume_id, size):
|
2020-04-24 15:38:18 +00:00
|
|
|
import time
|
2021-10-02 12:45:17 +00:00
|
|
|
from subprocess import CalledProcessError
|
2020-06-13 23:47:32 +00:00
|
|
|
from pathlib import Path
|
|
|
|
|
2021-10-02 12:45:17 +00:00
|
|
|
import rawfile_util
|
|
|
|
from volume_schema import LATEST_SCHEMA_VERSION
|
2020-04-24 11:48:09 +00:00
|
|
|
from util import run
|
2021-07-02 16:01:01 +00:00
|
|
|
from consts import RESOURCE_EXHAUSTED_EXIT_CODE
|
|
|
|
|
2020-04-24 15:38:18 +00:00
|
|
|
img_dir = rawfile_util.img_dir(volume_id)
|
2020-06-13 23:47:32 +00:00
|
|
|
img_dir.mkdir(exist_ok=True)
|
|
|
|
img_file = Path(f"{img_dir}/disk.img")
|
|
|
|
if img_file.exists():
|
|
|
|
return
|
2020-04-24 15:38:18 +00:00
|
|
|
rawfile_util.patch_metadata(
|
|
|
|
volume_id,
|
|
|
|
{
|
2020-07-16 15:24:04 +00:00
|
|
|
"schema_version": LATEST_SCHEMA_VERSION,
|
2020-04-24 15:38:18 +00:00
|
|
|
"volume_id": volume_id,
|
|
|
|
"created_at": time.time(),
|
2020-06-13 23:47:32 +00:00
|
|
|
"img_file": img_file.as_posix(),
|
2020-04-24 15:38:18 +00:00
|
|
|
"size": size,
|
|
|
|
},
|
|
|
|
)
|
2020-04-24 11:48:09 +00:00
|
|
|
run(f"truncate -s {size} {img_file}")
|
Support online volume expansion
Summary:
Online volume expansion is a 2 phase process:
1. The backing storage, in this case the raw file, needs to be resized. (i.e. `truncate -s`)
2. The node should be notified, so that it can both refresh its device capacity (i.e. `losetup -c`) and resize the filesystem (`resize2fs`) accordingly.
Although in our case both steps could be performed on the node itself, for the sake of following the semantics of how volume expansion works, we perform step 1 from the controller, and step 2 from the node.
Also, the `external-resizer` component is added which watches for PVC size updates, and notifies the CSI controller about it.
Test Plan:
Setup:
- Deploy
- Create a rawfile-backed pvc, and attach a Deployment to it
- Keep an eye on `rawfile` pod logs in `kube-system` namespace to see if any errors pop out during all scenarios
Scenario 1:
- Increase the size of the pvc
- Exec into the pod and verify that the volume is resized indeed (using `df`)
Scenario 2:
- Decrease deployment's replica to 0
- Increase the size of the pvc. Wait for a couple of minutes.
- Increase deployment's replica to 1
- Exec into the pod and verify that the volume is resized indeed.
Reviewers: bghadiri, mhyousefi, h.marvi, sina_rad
Reviewed By: bghadiri, mhyousefi, sina_rad
Differential Revision: https://phab.hamravesh.ir/D817
2020-06-12 12:12:49 +00:00
|
|
|
|
|
|
|
|
2021-10-02 12:45:17 +00:00
|
|
|
def get_capacity():
|
|
|
|
import rawfile_util
|
|
|
|
|
2021-10-07 14:39:59 +00:00
|
|
|
cap = rawfile_util.get_capacity()
|
|
|
|
return max(0, cap)
|
2021-10-02 12:45:17 +00:00
|
|
|
|
|
|
|
|
Support online volume expansion
Summary:
Online volume expansion is a 2 phase process:
1. The backing storage, in this case the raw file, needs to be resized. (i.e. `truncate -s`)
2. The node should be notified, so that it can both refresh its device capacity (i.e. `losetup -c`) and resize the filesystem (`resize2fs`) accordingly.
Although in our case both steps could be performed on the node itself, for the sake of following the semantics of how volume expansion works, we perform step 1 from the controller, and step 2 from the node.
Also, the `external-resizer` component is added which watches for PVC size updates, and notifies the CSI controller about it.
Test Plan:
Setup:
- Deploy
- Create a rawfile-backed pvc, and attach a Deployment to it
- Keep an eye on `rawfile` pod logs in `kube-system` namespace to see if any errors pop out during all scenarios
Scenario 1:
- Increase the size of the pvc
- Exec into the pod and verify that the volume is resized indeed (using `df`)
Scenario 2:
- Decrease deployment's replica to 0
- Increase the size of the pvc. Wait for a couple of minutes.
- Increase deployment's replica to 1
- Exec into the pod and verify that the volume is resized indeed.
Reviewers: bghadiri, mhyousefi, h.marvi, sina_rad
Reviewed By: bghadiri, mhyousefi, sina_rad
Differential Revision: https://phab.hamravesh.ir/D817
2020-06-12 12:12:49 +00:00
|
|
|
@remote_fn
|
|
|
|
def expand_rawfile(volume_id, size):
|
|
|
|
import rawfile_util
|
2021-07-02 16:01:01 +00:00
|
|
|
|
Support online volume expansion
Summary:
Online volume expansion is a 2 phase process:
1. The backing storage, in this case the raw file, needs to be resized. (i.e. `truncate -s`)
2. The node should be notified, so that it can both refresh its device capacity (i.e. `losetup -c`) and resize the filesystem (`resize2fs`) accordingly.
Although in our case both steps could be performed on the node itself, for the sake of following the semantics of how volume expansion works, we perform step 1 from the controller, and step 2 from the node.
Also, the `external-resizer` component is added which watches for PVC size updates, and notifies the CSI controller about it.
Test Plan:
Setup:
- Deploy
- Create a rawfile-backed pvc, and attach a Deployment to it
- Keep an eye on `rawfile` pod logs in `kube-system` namespace to see if any errors pop out during all scenarios
Scenario 1:
- Increase the size of the pvc
- Exec into the pod and verify that the volume is resized indeed (using `df`)
Scenario 2:
- Decrease deployment's replica to 0
- Increase the size of the pvc. Wait for a couple of minutes.
- Increase deployment's replica to 1
- Exec into the pod and verify that the volume is resized indeed.
Reviewers: bghadiri, mhyousefi, h.marvi, sina_rad
Reviewed By: bghadiri, mhyousefi, sina_rad
Differential Revision: https://phab.hamravesh.ir/D817
2020-06-12 12:12:49 +00:00
|
|
|
from util import run
|
2021-07-02 16:01:01 +00:00
|
|
|
from consts import RESOURCE_EXHAUSTED_EXIT_CODE
|
Support online volume expansion
Summary:
Online volume expansion is a 2 phase process:
1. The backing storage, in this case the raw file, needs to be resized. (i.e. `truncate -s`)
2. The node should be notified, so that it can both refresh its device capacity (i.e. `losetup -c`) and resize the filesystem (`resize2fs`) accordingly.
Although in our case both steps could be performed on the node itself, for the sake of following the semantics of how volume expansion works, we perform step 1 from the controller, and step 2 from the node.
Also, the `external-resizer` component is added which watches for PVC size updates, and notifies the CSI controller about it.
Test Plan:
Setup:
- Deploy
- Create a rawfile-backed pvc, and attach a Deployment to it
- Keep an eye on `rawfile` pod logs in `kube-system` namespace to see if any errors pop out during all scenarios
Scenario 1:
- Increase the size of the pvc
- Exec into the pod and verify that the volume is resized indeed (using `df`)
Scenario 2:
- Decrease deployment's replica to 0
- Increase the size of the pvc. Wait for a couple of minutes.
- Increase deployment's replica to 1
- Exec into the pod and verify that the volume is resized indeed.
Reviewers: bghadiri, mhyousefi, h.marvi, sina_rad
Reviewed By: bghadiri, mhyousefi, sina_rad
Differential Revision: https://phab.hamravesh.ir/D817
2020-06-12 12:12:49 +00:00
|
|
|
|
|
|
|
img_file = rawfile_util.img_file(volume_id)
|
2021-07-02 16:01:01 +00:00
|
|
|
size_inc = size - rawfile_util.metadata(volume_id)["size"]
|
|
|
|
if size_inc <= 0:
|
2020-06-13 23:47:32 +00:00
|
|
|
return
|
2021-07-02 16:01:01 +00:00
|
|
|
|
Support online volume expansion
Summary:
Online volume expansion is a 2 phase process:
1. The backing storage, in this case the raw file, needs to be resized. (i.e. `truncate -s`)
2. The node should be notified, so that it can both refresh its device capacity (i.e. `losetup -c`) and resize the filesystem (`resize2fs`) accordingly.
Although in our case both steps could be performed on the node itself, for the sake of following the semantics of how volume expansion works, we perform step 1 from the controller, and step 2 from the node.
Also, the `external-resizer` component is added which watches for PVC size updates, and notifies the CSI controller about it.
Test Plan:
Setup:
- Deploy
- Create a rawfile-backed pvc, and attach a Deployment to it
- Keep an eye on `rawfile` pod logs in `kube-system` namespace to see if any errors pop out during all scenarios
Scenario 1:
- Increase the size of the pvc
- Exec into the pod and verify that the volume is resized indeed (using `df`)
Scenario 2:
- Decrease deployment's replica to 0
- Increase the size of the pvc. Wait for a couple of minutes.
- Increase deployment's replica to 1
- Exec into the pod and verify that the volume is resized indeed.
Reviewers: bghadiri, mhyousefi, h.marvi, sina_rad
Reviewed By: bghadiri, mhyousefi, sina_rad
Differential Revision: https://phab.hamravesh.ir/D817
2020-06-12 12:12:49 +00:00
|
|
|
rawfile_util.patch_metadata(
|
2021-07-02 14:20:45 +00:00
|
|
|
volume_id,
|
|
|
|
{"size": size},
|
Support online volume expansion
Summary:
Online volume expansion is a 2 phase process:
1. The backing storage, in this case the raw file, needs to be resized. (i.e. `truncate -s`)
2. The node should be notified, so that it can both refresh its device capacity (i.e. `losetup -c`) and resize the filesystem (`resize2fs`) accordingly.
Although in our case both steps could be performed on the node itself, for the sake of following the semantics of how volume expansion works, we perform step 1 from the controller, and step 2 from the node.
Also, the `external-resizer` component is added which watches for PVC size updates, and notifies the CSI controller about it.
Test Plan:
Setup:
- Deploy
- Create a rawfile-backed pvc, and attach a Deployment to it
- Keep an eye on `rawfile` pod logs in `kube-system` namespace to see if any errors pop out during all scenarios
Scenario 1:
- Increase the size of the pvc
- Exec into the pod and verify that the volume is resized indeed (using `df`)
Scenario 2:
- Decrease deployment's replica to 0
- Increase the size of the pvc. Wait for a couple of minutes.
- Increase deployment's replica to 1
- Exec into the pod and verify that the volume is resized indeed.
Reviewers: bghadiri, mhyousefi, h.marvi, sina_rad
Reviewed By: bghadiri, mhyousefi, sina_rad
Differential Revision: https://phab.hamravesh.ir/D817
2020-06-12 12:12:49 +00:00
|
|
|
)
|
|
|
|
run(f"truncate -s {size} {img_file}")
|
2022-02-17 13:56:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
@contextmanager
|
|
|
|
def mount_root_subvol(volume_id):
|
|
|
|
import tempfile
|
|
|
|
import pathlib
|
|
|
|
|
|
|
|
import rawfile_util
|
|
|
|
from util import run
|
|
|
|
|
|
|
|
root_subvol = tempfile.mkdtemp(prefix="rawfile-")
|
|
|
|
|
|
|
|
img_file = rawfile_util.img_file(volume_id)
|
|
|
|
loop_dev = rawfile_util.attach_loop(img_file)
|
|
|
|
|
|
|
|
run(f"mount -t btrfs -o subvolid=0 {loop_dev} {root_subvol}")
|
|
|
|
try:
|
|
|
|
yield root_subvol
|
|
|
|
finally:
|
|
|
|
run(f"umount {root_subvol}")
|
|
|
|
pathlib.Path(root_subvol).rmdir()
|
|
|
|
|
|
|
|
|
|
|
|
def btrfs_delete_snapshot(volume_id, name):
|
|
|
|
import btrfsutil
|
|
|
|
|
|
|
|
with mount_root_subvol(volume_id) as root_subvol:
|
|
|
|
snapshots_dir = f"{root_subvol}/.snapshots"
|
|
|
|
snapshot_path = f"{snapshots_dir}/{name}"
|
|
|
|
btrfsutil.delete_subvolume(snapshot_path)
|
|
|
|
|
|
|
|
|
|
|
|
def btrfs_create_snapshot(volume_id, name):
|
|
|
|
import btrfsutil
|
|
|
|
import time
|
|
|
|
import pathlib
|
|
|
|
|
|
|
|
# TODO: check fstype
|
|
|
|
|
|
|
|
with mount_root_subvol(volume_id) as root_subvol:
|
|
|
|
default_subvol_id = btrfsutil.get_default_subvolume(root_subvol)
|
|
|
|
default_subvol = btrfsutil.subvolume_path(root_subvol, default_subvol_id)
|
|
|
|
default_subvol = f"{root_subvol}/{default_subvol}"
|
|
|
|
|
|
|
|
snapshots_dir = f"{root_subvol}/.snapshots"
|
|
|
|
pathlib.Path(snapshots_dir).mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
|
|
snapshot_subvol = f"{snapshots_dir}/{name}"
|
|
|
|
btrfsutil.create_snapshot(default_subvol, snapshot_subvol, read_only=True)
|
|
|
|
|
|
|
|
snapshot_id = f"{volume_id}/{name}"
|
|
|
|
creation_time_ns = time.time_ns()
|
|
|
|
return snapshot_id, creation_time_ns
|