diff --git a/.gitignore b/.gitignore index 15a6fcf101b4542345edf8fb1bad202aafdb8850..c35494c789829bc123264d2bcc0b167051931d2f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ __pycache__/ .pytest_cache/ .vscode/ rwm.conf +rwm-*.conf testfile* -venv/ \ No newline at end of file +venv/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e0d9a0d6e6011dec31dffc57a9855f6e8db4bdef..8c2683c1e8fbfdf59be996713ff4fbbac4f3571e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,12 +4,15 @@ image: debian:bookworm stages: - code_quality +variables: + GIT_STRATEGY: clone + code_quality: stage: code_quality before_script: - - apt-get update && apt-get -y install make - - make install - - make venv + - python3 -m venv venv + - venv/bin/pip install -U pip + - venv/bin/pip install -r requirements.lock script: - . venv/bin/activate && make coverage - . venv/bin/activate && make lint diff --git a/Makefile b/Makefile index cc7a31f5a8883e1fb310a06439bf17884d9e3912..fcee2a42cc1a6dcea744ae52def9b9db7a547581 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,14 @@ -all: lint +all: coverage lint install: - apt-get -y install awscli make python3-cryptography python3-tabulate rclone restic yamllint + apt-get -y install awscli python3-cryptography python3-tabulate rclone restic yamllint -venv: - apt-get -y install python3-venv +install-dev: + apt-get -y install python3-venv snapd python3 -m venv venv venv/bin/pip install -U pip venv/bin/pip install -r requirements.lock -venv-refresh: - apt-get -y install python3-venv - rm -r venv - python3 -m venv venv - venv/bin/pip install -U pip - venv/bin/pip install -r requirements.txt - freeze: @pip freeze | grep -v '^pkg[-_]resources=' @@ -34,3 +27,24 @@ test: coverage: coverage run --source rwm -m pytest tests/ -x -vv coverage report --show-missing --fail-under 100 + +microceph-service: + snap install microceph + snap refresh --hold microceph + /snap/bin/microceph cluster bootstrap + /snap/bin/microceph disk add loop,1G,3 + /snap/bin/microceph enable rgw + while true; do /snap/bin/ceph status | grep "HEALTH_OK" && break; done + # required for gitlab runner shell executor which runs as non-privileged user + ln -sf /var/snap/microceph/current/conf /etc/ceph + chmod 644 /etc/ceph/* + +microceph-cleanup: + snap remove microceph --purge + rm /etc/ceph + +microceph: microceph-cleanup microceph-service + +runner: + apt-get install -y ansible + ansible-playbook ansible/playbook_gitlab_runner.yml diff --git a/README.md b/README.md index 95314b40348705c8b154d15d4311ed6dab3f608d..5b0a1eb9f9d042a8efdcf9689cbd6fcb3da22248 100644 --- a/README.md +++ b/README.md @@ -113,14 +113,22 @@ rwm restic mount /mnt/restore ## Development ``` -git clone git@gitlab.flab.cesnet.cz:bodik/rwm.git /opt/rwm +git clone git@gitlab.cesnet.cz:radoslav_bodo/rwm.git /opt/rwm cd /opt/rwm make install -make venv +make install-dev +make microceph-service . venv/bin/activate +make coverage lint ``` -## Mainline backups +## Gitlab Runner -TBD +``` +git clone git@gitlab.cesnet.cz:radoslav_bodo/rwm.git /opt/rwm +cd /opt/rwm +export RUNNER_URL= +export RUNNER_TOKEN= +make runner +``` \ No newline at end of file diff --git a/ansible/playbook_gitlab_runner.yml b/ansible/playbook_gitlab_runner.yml new file mode 100644 index 0000000000000000000000000000000000000000..872beb9a713036892f40bc5c069970553284cffd --- /dev/null +++ b/ansible/playbook_gitlab_runner.yml @@ -0,0 +1,63 @@ +--- +- name: install rwm runner + hosts: localhost + vars: + runner_url: "{{ lookup('ansible.builtin.env', 'RUNNER_URL') }}" + runner_token: "{{ lookup('ansible.builtin.env', 'RUNNER_TOKEN') }}" + runner_config: | + concurrent = 1 + check_interval = 0 + shutdown_timeout = 0 + [session_server] + session_timeout = 1800 + [[runners]] + name = "rwmsnaprunner" + url = "{{ runner_url }}" + token = "{{ runner_token }}" + executor = "shell" + + handlers: + - name: gitlab-runner restart + service: + name: gitlab-runner + state: restarted + + tasks: + - name: gitlab-runner dependencies + apt: + name: + - apt-transport-https + - software-properties-common + - wget + state: present + + - name: gitlab-runner apt key + apt_key: + id: F6403F6544A38863DAA0B6E03F01618A51312F3F + url: https://packages.gitlab.com/runner/gitlab-runner/gpgkey + state: present + + - name: gitlab-runner apt repo + apt_repository: + repo: "deb https://packages.gitlab.com/runner/gitlab-runner/debian bookworm main" # yamllint disable-line rule:line-length + state: present + + - name: gitlab-runner package + apt: + name: + - gitlab-runner + + - name: gitlab-runner config + copy: + content: "{{ runner_config }}" + dest: /etc/gitlab-runner/config.toml + owner: root + group: root + mode: 0600 + notify: gitlab-runner restart + + - name: development env with microceph + shell: + cmd: make install install-dev microceph-service + chdir: /opt/rwm + creates: /snap/bin/microceph diff --git a/tests/conftest.py b/tests/conftest.py index 770f0cfc175a9958793467024c7a7dd9f159a374..32e709475069970710e514a6bf3ab836d4f53153 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,14 +1,32 @@ """pytest conftest""" +import json import os import shutil import socket +import subprocess from tempfile import mkdtemp +import boto3 import pytest from xprocess import ProcessStarter +@pytest.fixture +def tmpworkdir(): + """ + self cleaning temporary workdir + pytest tmpdir fixture has issues https://github.com/pytest-dev/pytest/issues/1120 + """ + + cwd = os.getcwd() + tmpdir = mkdtemp(prefix='rwmtest_') + os.chdir(tmpdir) + yield tmpdir + os.chdir(cwd) + shutil.rmtree(tmpdir) + + @pytest.fixture def motoserver(xprocess): """mocking s3 server fixture""" @@ -30,15 +48,48 @@ def motoserver(xprocess): @pytest.fixture -def tmpworkdir(): - """ - self cleaning temporary workdir - pytest tmpdir fixture has issues https://github.com/pytest-dev/pytest/issues/1120 - """ +def microceph(): + """microceph s3 server fixture""" - cwd = os.getcwd() - tmpdir = mkdtemp(prefix='rwmtest_') - os.chdir(tmpdir) - yield tmpdir - os.chdir(cwd) - shutil.rmtree(tmpdir) + yield "http://localhost:80" + + +def rgwuser(microceph_url, name): + """rgwuser fixture""" + + subprocess.run( + ["/snap/bin/radosgw-admin", "user", "rm", f"--uid={name}", "--purge-data"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=False + ) + proc = subprocess.run( + ["/snap/bin/radosgw-admin", "user", "create", f"--uid={name}", f"--display-name=rwguser_{name}"], + check=True, + capture_output=True, + text=True, + ) + + user = json.loads(proc.stdout) + yield boto3.resource( + 's3', + endpoint_url=microceph_url, + aws_access_key_id=user["keys"][0]["access_key"], + aws_secret_access_key=user["keys"][0]["secret_key"] + ) + + subprocess.run(["/snap/bin/radosgw-admin", "user", "rm", f"--uid={name}", "--purge-data"], check=True) + + +@pytest.fixture +def rgwuser_test1(microceph): # pylint: disable=redefined-outer-name, unused-argument + """rgwuser test1 stub""" + + yield from rgwuser(microceph, "test1") + + +@pytest.fixture +def rgwuser_test2(microceph): # pylint: disable=redefined-outer-name, unused-argument + """rgwuser test2 stub""" + + yield from rgwuser(microceph, "test2") diff --git a/tests/test_policies.py b/tests/test_policies.py new file mode 100644 index 0000000000000000000000000000000000000000..acd19db3f7d4ea38727ceca66287d8cefc5def2d --- /dev/null +++ b/tests/test_policies.py @@ -0,0 +1,33 @@ +"""rwm bucket policies tests""" + +import boto3 +import pytest + + +def test_microceph_defaults( + tmpworkdir: str, + microceph: str, + rgwuser_test1: boto3.resource, + rgwuser_test2: boto3.resource +): # pylint: disable=unused-argument + """test microceph defaults""" + + # bucket should not be present + test_bucket = "testbuckx" + assert test_bucket not in [x.name for x in rgwuser_test1.buckets.all()] + + # create bucket + rgwuser_test1.create_bucket(Bucket=test_bucket) + assert test_bucket in [x.name for x in rgwuser_test1.buckets.all()] + + # list from other identity, check it is not visible + assert test_bucket not in [x.name for x in rgwuser_test2.buckets.all()] + # but already exist + with pytest.raises(rgwuser_test2.meta.client.exceptions.BucketAlreadyExists): + rgwuser_test2.create_bucket(Bucket=test_bucket) + + # belongs to expected user + assert rgwuser_test1.Bucket(test_bucket).Acl().owner["ID"] == "test1" + # but unaccessible by other user + with pytest.raises(rgwuser_test2.meta.client.exceptions.ClientError, match=r"AccessDenied"): + assert rgwuser_test2.Bucket(test_bucket).Acl().owner["ID"] == "test1"