Compare commits

..

1 Commits

Author SHA1 Message Date
Vitaliy Filippov e1a0e89a6b node.js binding fixes 2024-08-04 15:54:20 +03:00
185 changed files with 1160 additions and 8260 deletions

View File

@ -22,7 +22,7 @@ RUN apt-get update
RUN apt-get -y install etcd qemu-system-x86 qemu-block-extra qemu-utils fio libasan5 \ RUN apt-get -y install etcd qemu-system-x86 qemu-block-extra qemu-utils fio libasan5 \
liburing1 liburing-dev libgoogle-perftools-dev devscripts libjerasure-dev cmake libibverbs-dev libisal-dev liburing1 liburing-dev libgoogle-perftools-dev devscripts libjerasure-dev cmake libibverbs-dev libisal-dev
RUN apt-get -y build-dep fio qemu=`dpkg -s qemu-system-x86|grep ^Version:|awk '{print $2}'` RUN apt-get -y build-dep fio qemu=`dpkg -s qemu-system-x86|grep ^Version:|awk '{print $2}'`
RUN apt-get update && apt-get -y install jq lp-solve sudo nfs-common fdisk parted RUN apt-get -y install jq lp-solve sudo nfs-common
RUN apt-get --download-only source fio qemu=`dpkg -s qemu-system-x86|grep ^Version:|awk '{print $2}'` RUN apt-get --download-only source fio qemu=`dpkg -s qemu-system-x86|grep ^Version:|awk '{print $2}'`
RUN set -ex; \ RUN set -ex; \

View File

@ -288,24 +288,6 @@ jobs:
echo "" echo ""
done done
test_create_halfhost:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- name: Run test
id: test
timeout-minutes: 3
run: /root/vitastor/tests/test_create_halfhost.sh
- name: Print logs
if: always() && steps.test.outcome == 'failure'
run: |
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
echo "-------- $i --------"
cat $i
echo ""
done
test_failure_domain: test_failure_domain:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build
@ -576,24 +558,6 @@ jobs:
echo "" echo ""
done done
test_dd:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- name: Run test
id: test
timeout-minutes: 3
run: /root/vitastor/tests/test_dd.sh
- name: Print logs
if: always() && steps.test.outcome == 'failure'
run: |
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
echo "-------- $i --------"
cat $i
echo ""
done
test_root_node: test_root_node:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build
@ -846,60 +810,6 @@ jobs:
echo "" echo ""
done done
test_resize:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- name: Run test
id: test
timeout-minutes: 3
run: /root/vitastor/tests/test_resize.sh
- name: Print logs
if: always() && steps.test.outcome == 'failure'
run: |
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
echo "-------- $i --------"
cat $i
echo ""
done
test_resize_auto:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- name: Run test
id: test
timeout-minutes: 3
run: /root/vitastor/tests/test_resize_auto.sh
- name: Print logs
if: always() && steps.test.outcome == 'failure'
run: |
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
echo "-------- $i --------"
cat $i
echo ""
done
test_snapshot_pool2:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- name: Run test
id: test
timeout-minutes: 3
run: /root/vitastor/tests/test_snapshot_pool2.sh
- name: Print logs
if: always() && steps.test.outcome == 'failure'
run: |
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
echo "-------- $i --------"
cat $i
echo ""
done
test_osd_tags: test_osd_tags:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build

View File

@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 2.8.12)
project(vitastor) project(vitastor)
set(VITASTOR_VERSION "1.9.3") set(VITASTOR_VERSION "1.7.1")
add_subdirectory(src) add_subdirectory(src)

View File

@ -1,4 +1,4 @@
# Vitastor ## Vitastor
[Read English version](README.md) [Read English version](README.md)
@ -19,10 +19,10 @@ Vitastor нацелен в первую очередь на SSD и SSD+HDD кл
TCP и RDMA и на хорошем железе может достигать задержки 4 КБ чтения и записи на уровне ~0.1 мс, TCP и RDMA и на хорошем железе может достигать задержки 4 КБ чтения и записи на уровне ~0.1 мс,
что примерно в 10 раз быстрее, чем Ceph и другие популярные программные СХД. что примерно в 10 раз быстрее, чем Ceph и другие популярные программные СХД.
Vitastor поддерживает QEMU-драйвер, протоколы NBD и NFS, драйверы OpenStack, OpenNebula, Proxmox, Kubernetes. Vitastor поддерживает QEMU-драйвер, протоколы NBD и NFS, драйверы OpenStack, Proxmox, Kubernetes.
Другие драйверы могут также быть легко реализованы. Другие драйверы могут также быть легко реализованы.
Подробности смотрите в документации по ссылкам. Можете начать отсюда: [Быстрый старт](docs/intro/quickstart.ru.md). Подробности смотрите в документации по ссылкам ниже.
## Презентации и записи докладов ## Презентации и записи докладов
@ -42,7 +42,6 @@ Vitastor поддерживает QEMU-драйвер, протоколы NBD и
- Установка - Установка
- [Пакеты](docs/installation/packages.ru.md) - [Пакеты](docs/installation/packages.ru.md)
- [Proxmox](docs/installation/proxmox.ru.md) - [Proxmox](docs/installation/proxmox.ru.md)
- [OpenNebula](docs/installation/opennebula.ru.md)
- [OpenStack](docs/installation/openstack.ru.md) - [OpenStack](docs/installation/openstack.ru.md)
- [Kubernetes CSI](docs/installation/kubernetes.ru.md) - [Kubernetes CSI](docs/installation/kubernetes.ru.md)
- [Сборка из исходных кодов](docs/installation/source.ru.md) - [Сборка из исходных кодов](docs/installation/source.ru.md)
@ -51,7 +50,7 @@ Vitastor поддерживает QEMU-драйвер, протоколы NBD и
- Параметры - Параметры
- [Общие](docs/config/common.ru.md) - [Общие](docs/config/common.ru.md)
- [Сетевые](docs/config/network.ru.md) - [Сетевые](docs/config/network.ru.md)
- [Клиентский код](docs/config/client.ru.md) - [Клиентский код](docs/config/client.en.md)
- [Глобальные дисковые параметры](docs/config/layout-cluster.ru.md) - [Глобальные дисковые параметры](docs/config/layout-cluster.ru.md)
- [Дисковые параметры OSD](docs/config/layout-osd.ru.md) - [Дисковые параметры OSD](docs/config/layout-osd.ru.md)
- [Прочие параметры OSD](docs/config/osd.ru.md) - [Прочие параметры OSD](docs/config/osd.ru.md)

View File

@ -19,10 +19,10 @@ supports TCP and RDMA and may achieve 4 KB read and write latency as low as ~0.1
with proper hardware which is ~10 times faster than other popular SDS's like Ceph with proper hardware which is ~10 times faster than other popular SDS's like Ceph
or internal systems of public clouds. or internal systems of public clouds.
Vitastor supports QEMU, NBD, NFS protocols, OpenStack, OpenNebula, Proxmox, Kubernetes drivers. Vitastor supports QEMU, NBD, NFS protocols, OpenStack, Proxmox, Kubernetes drivers.
More drivers may be created easily. More drivers may be created easily.
Read more details in the documentation. You can start from here: [Quick Start](docs/intro/quickstart.en.md). Read more details below in the documentation.
## Talks and presentations ## Talks and presentations
@ -42,7 +42,6 @@ Read more details in the documentation. You can start from here: [Quick Start](d
- Installation - Installation
- [Packages](docs/installation/packages.en.md) - [Packages](docs/installation/packages.en.md)
- [Proxmox](docs/installation/proxmox.en.md) - [Proxmox](docs/installation/proxmox.en.md)
- [OpenNebula](docs/installation/opennebula.en.md)
- [OpenStack](docs/installation/openstack.en.md) - [OpenStack](docs/installation/openstack.en.md)
- [Kubernetes CSI](docs/installation/kubernetes.en.md) - [Kubernetes CSI](docs/installation/kubernetes.en.md)
- [Building from Source](docs/installation/source.en.md) - [Building from Source](docs/installation/source.en.md)

View File

@ -1,4 +1,4 @@
VITASTOR_VERSION ?= v1.9.3 VITASTOR_VERSION ?= v1.7.1
all: build push all: build push

View File

@ -49,7 +49,7 @@ spec:
capabilities: capabilities:
add: ["SYS_ADMIN"] add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true allowPrivilegeEscalation: true
image: vitalif/vitastor-csi:v1.9.3 image: vitalif/vitastor-csi:v1.7.1
args: args:
- "--node=$(NODE_ID)" - "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)" - "--endpoint=$(CSI_ENDPOINT)"

View File

@ -121,7 +121,7 @@ spec:
privileged: true privileged: true
capabilities: capabilities:
add: ["SYS_ADMIN"] add: ["SYS_ADMIN"]
image: vitalif/vitastor-csi:v1.9.3 image: vitalif/vitastor-csi:v1.7.1
args: args:
- "--node=$(NODE_ID)" - "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)" - "--endpoint=$(CSI_ENDPOINT)"

View File

@ -3,10 +3,10 @@ module vitastor.io/csi
go 1.15 go 1.15
require ( require (
github.com/container-storage-interface/spec v1.8.0 github.com/container-storage-interface/spec v1.4.0
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/kubernetes-csi/csi-lib-utils v0.9.1 github.com/kubernetes-csi/csi-lib-utils v0.9.1
golang.org/x/net v0.7.0 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/grpc v1.33.1 google.golang.org/grpc v1.33.1
google.golang.org/protobuf v1.24.0 google.golang.org/protobuf v1.24.0

View File

@ -41,8 +41,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
github.com/container-storage-interface/spec v1.8.0 h1:D0vhF3PLIZwlwZEf2eNbpujGCNwspwTYf2idJRJx4xI= github.com/container-storage-interface/spec v1.4.0 h1:ozAshSKxpJnYUfmkpZCTYyF/4MYeYlhdXbAvPvfGmkg=
github.com/container-storage-interface/spec v1.8.0/go.mod h1:ROLik+GhPslwwWRNFF1KasPzroNARibH2rfz1rkg4H0= github.com/container-storage-interface/spec v1.4.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -182,7 +182,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@ -196,7 +195,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -215,7 +213,6 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -231,10 +228,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -245,7 +240,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -265,22 +259,13 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -301,10 +286,8 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -5,7 +5,7 @@ package vitastor
const ( const (
vitastorCSIDriverName = "csi.vitastor.io" vitastorCSIDriverName = "csi.vitastor.io"
vitastorCSIDriverVersion = "1.9.3" vitastorCSIDriverVersion = "1.7.1"
) )
// Config struct fills the parameters of request or user input // Config struct fills the parameters of request or user input

View File

@ -8,9 +8,11 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings" "strings"
"bytes"
"strconv" "strconv"
"time" "time"
"os" "os"
"os/exec"
"io/ioutil" "io/ioutil"
"github.com/kubernetes-csi/csi-lib-utils/protosanitizer" "github.com/kubernetes-csi/csi-lib-utils/protosanitizer"
@ -112,6 +114,22 @@ func GetConnectionParams(params map[string]string) (map[string]string, error)
return ctxVars, nil return ctxVars, nil
} }
func system(program string, args ...string) ([]byte, []byte, error)
{
klog.Infof("Running "+program+" "+strings.Join(args, " "))
c := exec.Command(program, args...)
var stdout, stderr bytes.Buffer
c.Stdout, c.Stderr = &stdout, &stderr
err := c.Run()
if (err != nil)
{
stdoutStr, stderrStr := string(stdout.Bytes()), string(stderr.Bytes())
klog.Errorf(program+" "+strings.Join(args, " ")+" failed: %s, status %s\n", stdoutStr+stderrStr, err)
return nil, nil, status.Error(codes.Internal, stdoutStr+stderrStr+" (status "+err.Error()+")")
}
return stdout.Bytes(), stderr.Bytes(), nil
}
func invokeCLI(ctxVars map[string]string, args []string) ([]byte, error) func invokeCLI(ctxVars map[string]string, args []string) ([]byte, error)
{ {
if (ctxVars["configPath"] != "") if (ctxVars["configPath"] != "")
@ -140,12 +158,6 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
return nil, status.Error(codes.InvalidArgument, "volume capabilities is a required field") return nil, status.Error(codes.InvalidArgument, "volume capabilities is a required field")
} }
err := cs.checkCaps(volumeCapabilities)
if (err != nil)
{
return nil, err
}
etcdVolumePrefix := req.Parameters["etcdVolumePrefix"] etcdVolumePrefix := req.Parameters["etcdVolumePrefix"]
poolId, _ := strconv.ParseUint(req.Parameters["poolId"], 10, 64) poolId, _ := strconv.ParseUint(req.Parameters["poolId"], 10, 64)
if (poolId == 0) if (poolId == 0)
@ -289,44 +301,13 @@ func (cs *ControllerServer) ValidateVolumeCapabilities(ctx context.Context, req
return nil, status.Error(codes.InvalidArgument, "volumeCapabilities is nil") return nil, status.Error(codes.InvalidArgument, "volumeCapabilities is nil")
} }
err := cs.checkCaps(volumeCapabilities)
if (err != nil)
{
return nil, err
}
return &csi.ValidateVolumeCapabilitiesResponse{
Confirmed: &csi.ValidateVolumeCapabilitiesResponse_Confirmed{
VolumeCapabilities: req.VolumeCapabilities,
},
}, nil
}
func (cs *ControllerServer) checkCaps(volumeCapabilities []*csi.VolumeCapability) error
{
var volumeCapabilityAccessModes []*csi.VolumeCapability_AccessMode var volumeCapabilityAccessModes []*csi.VolumeCapability_AccessMode
for _, mode := range []csi.VolumeCapability_AccessMode_Mode{ for _, mode := range []csi.VolumeCapability_AccessMode_Mode{
csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY,
csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
csi.VolumeCapability_AccessMode_SINGLE_NODE_SINGLE_WRITER,
csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER,
} {
volumeCapabilityAccessModes = append(volumeCapabilityAccessModes, &csi.VolumeCapability_AccessMode{Mode: mode})
}
for _, capability := range volumeCapabilities
{
if (capability.GetBlock() != nil)
{
for _, mode := range []csi.VolumeCapability_AccessMode_Mode{
csi.VolumeCapability_AccessMode_MULTI_NODE_SINGLE_WRITER,
csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER, csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
} { } {
volumeCapabilityAccessModes = append(volumeCapabilityAccessModes, &csi.VolumeCapability_AccessMode{Mode: mode}) volumeCapabilityAccessModes = append(volumeCapabilityAccessModes, &csi.VolumeCapability_AccessMode{Mode: mode})
} }
break
}
}
capabilitySupport := false capabilitySupport := false
for _, capability := range volumeCapabilities for _, capability := range volumeCapabilities
@ -342,10 +323,14 @@ func (cs *ControllerServer) checkCaps(volumeCapabilities []*csi.VolumeCapability
if (!capabilitySupport) if (!capabilitySupport)
{ {
return status.Errorf(codes.NotFound, "%v not supported", volumeCapabilities) return nil, status.Errorf(codes.NotFound, "%v not supported", req.GetVolumeCapabilities())
} }
return nil return &csi.ValidateVolumeCapabilitiesResponse{
Confirmed: &csi.ValidateVolumeCapabilitiesResponse_Confirmed{
VolumeCapabilities: req.VolumeCapabilities,
},
}, nil
} }
// ListVolumes returns a list of volumes // ListVolumes returns a list of volumes

View File

@ -227,32 +227,7 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
isBlock := req.GetVolumeCapability().GetBlock() != nil isBlock := req.GetVolumeCapability().GetBlock() != nil
// Check that it's not already mounted // Check that it's not already mounted
notmnt, err := mount.IsNotMountPoint(ns.mounter, targetPath) _, err = mount.IsNotMountPoint(ns.mounter, targetPath)
if (err == nil)
{
if (!notmnt)
{
klog.Errorf("target path %s is already mounted", targetPath)
return nil, fmt.Errorf("target path %s is already mounted", targetPath)
}
var finfo os.FileInfo
finfo, err = os.Stat(targetPath)
if (err != nil)
{
klog.Errorf("failed to stat %s: %v", targetPath, err)
return nil, err
}
if (finfo.IsDir() != (!isBlock))
{
err = os.Remove(targetPath)
if (err != nil)
{
klog.Errorf("failed to remove %s (to recreate it with correct type): %v", targetPath, err)
return nil, err
}
err = os.ErrNotExist
}
}
if (err != nil) if (err != nil)
{ {
if (os.IsNotExist(err)) if (os.IsNotExist(err))
@ -305,7 +280,6 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
diskMounter := &mount.SafeFormatAndMount{Interface: ns.mounter, Exec: utilexec.New()} diskMounter := &mount.SafeFormatAndMount{Interface: ns.mounter, Exec: utilexec.New()}
if (isBlock) if (isBlock)
{ {
klog.Infof("bind-mounting %s to %s", devicePath, targetPath)
err = diskMounter.Mount(devicePath, targetPath, "", []string{"bind"}) err = diskMounter.Mount(devicePath, targetPath, "", []string{"bind"})
} }
else else
@ -335,40 +309,39 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
readOnly := Contains(opt, "ro") readOnly := Contains(opt, "ro")
if (existingFormat == "" && !readOnly) if (existingFormat == "" && !readOnly)
{ {
var cmdOut []byte
switch fsType switch fsType
{ {
case "ext4": case "ext4":
args := []string{"-m0", "-Enodiscard,lazy_itable_init=1,lazy_journal_init=1", devicePath} args := []string{"-m0", "-Enodiscard,lazy_itable_init=1,lazy_journal_init=1", devicePath}
_, err = systemCombined("mkfs.ext4", args...) cmdOut, err = diskMounter.Exec.Command("mkfs.ext4", args...).CombinedOutput()
case "xfs": case "xfs":
_, err = systemCombined("mkfs.xfs", "-K", devicePath) cmdOut, err = diskMounter.Exec.Command("mkfs.xfs", "-K", devicePath).CombinedOutput()
} }
if (err != nil) if (err != nil)
{ {
klog.Errorf("failed to run mkfs error: %v, output: %v", err, string(cmdOut))
goto unmap goto unmap
} }
} }
klog.Infof("formatting and mounting %s to %s with FS %s, options: %v", devicePath, targetPath, fsType, opt)
err = diskMounter.FormatAndMount(devicePath, targetPath, fsType, opt) err = diskMounter.FormatAndMount(devicePath, targetPath, fsType, opt)
if (err == nil)
{
klog.Infof("successfully mounted %s to %s", devicePath, targetPath)
}
// Try to run online resize on mount. // Try to run online resize on mount.
// FIXME: Implement online resize. It requires online resize support in vitastor-nbd. // FIXME: Implement online resize. It requires online resize support in vitastor-nbd.
if (err == nil && existingFormat != "" && !readOnly) if (err == nil && existingFormat != "" && !readOnly)
{ {
var cmdOut []byte
switch (fsType) switch (fsType)
{ {
case "ext4": case "ext4":
_, err = systemCombined("resize2fs", devicePath) cmdOut, err = diskMounter.Exec.Command("resize2fs", devicePath).CombinedOutput()
case "xfs": case "xfs":
_, err = systemCombined("xfs_growfs", devicePath) cmdOut, err = diskMounter.Exec.Command("xfs_growfs", devicePath).CombinedOutput()
} }
if (err != nil) if (err != nil)
{ {
klog.Errorf("failed to run resizefs error: %v, output: %v", err, string(cmdOut))
goto unmap goto unmap
} }
} }
@ -412,7 +385,7 @@ func (ns *NodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
defer ns.unlockVolume(ctxVars["configPath"]+":"+volName) defer ns.unlockVolume(ctxVars["configPath"]+":"+volName)
targetPath := req.GetStagingTargetPath() targetPath := req.GetStagingTargetPath()
devicePath, _, err := mount.GetDeviceNameFromMount(ns.mounter, targetPath) devicePath, refCount, err := mount.GetDeviceNameFromMount(ns.mounter, targetPath)
if (err != nil) if (err != nil)
{ {
if (os.IsNotExist(err)) if (os.IsNotExist(err))
@ -429,16 +402,6 @@ func (ns *NodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
return &csi.NodeUnstageVolumeResponse{}, nil return &csi.NodeUnstageVolumeResponse{}, nil
} }
refList, err := ns.mounter.GetMountRefs(targetPath)
if (err != nil)
{
return nil, err
}
if (len(refList) > 0)
{
klog.Warningf("%s is still referenced: %v", targetPath, refList)
}
// unmount // unmount
err = mount.CleanupMountPoint(targetPath, ns.mounter, false) err = mount.CleanupMountPoint(targetPath, ns.mounter, false)
if (err != nil) if (err != nil)
@ -447,7 +410,7 @@ func (ns *NodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
} }
// unmap device // unmap device
if (len(refList) == 0) if (refCount == 1)
{ {
if (!ns.useVduse) if (!ns.useVduse)
{ {
@ -488,20 +451,15 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
isBlock := req.GetVolumeCapability().GetBlock() != nil isBlock := req.GetVolumeCapability().GetBlock() != nil
// Check that stagingTargetPath is mounted // Check that stagingTargetPath is mounted
notmnt, err := mount.IsNotMountPoint(ns.mounter, stagingTargetPath) _, err = mount.IsNotMountPoint(ns.mounter, stagingTargetPath)
if (err != nil) if (err != nil)
{ {
klog.Errorf("staging path %v is not mounted: %w", stagingTargetPath, err) klog.Errorf("staging path %v is not mounted: %v", stagingTargetPath, err)
return nil, fmt.Errorf("staging path %v is not mounted: %w", stagingTargetPath, err) return nil, fmt.Errorf("staging path %v is not mounted: %v", stagingTargetPath, err)
}
else if (notmnt)
{
klog.Errorf("staging path %v is not mounted", stagingTargetPath)
return nil, fmt.Errorf("staging path %v is not mounted", stagingTargetPath)
} }
// Check that targetPath is not already mounted // Check that targetPath is not already mounted
notmnt, err = mount.IsNotMountPoint(ns.mounter, targetPath) _, err = mount.IsNotMountPoint(ns.mounter, targetPath)
if (err != nil) if (err != nil)
{ {
if (os.IsNotExist(err)) if (os.IsNotExist(err))
@ -536,11 +494,6 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
return nil, err return nil, err
} }
} }
else if (!notmnt)
{
klog.Errorf("target path %s is already mounted", targetPath)
return nil, fmt.Errorf("target path %s is already mounted", targetPath)
}
execArgs := []string{"--bind", stagingTargetPath, targetPath} execArgs := []string{"--bind", stagingTargetPath, targetPath}
if (req.GetReadonly()) if (req.GetReadonly())

View File

@ -4,7 +4,6 @@
package vitastor package vitastor
import ( import (
"bytes"
"errors" "errors"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -16,8 +15,6 @@ import (
"syscall" "syscall"
"k8s.io/klog" "k8s.io/klog"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
) )
func Contains(list []string, s string) bool func Contains(list []string, s string) bool
@ -76,10 +73,6 @@ func checkVduseSupport() bool
" For VDUSE you need at least Linux 5.15 and the following kernel modules: vdpa, virtio-vdpa, vduse.", " For VDUSE you need at least Linux 5.15 and the following kernel modules: vdpa, virtio-vdpa, vduse.",
) )
} }
else
{
klog.Infof("VDUSE support enabled successfully")
}
return vduse return vduse
} }
@ -104,7 +97,6 @@ func mapNbd(volName string, ctxVars map[string]string, readonly bool) (string, e
{ {
return "", fmt.Errorf("vitastor-nbd did not return the name of NBD device. output: %s", stderr) return "", fmt.Errorf("vitastor-nbd did not return the name of NBD device. output: %s", stderr)
} }
klog.Infof("Attached volume %s via NBD as %s", volName, dev)
return dev, err return dev, err
} }
@ -225,7 +217,6 @@ func mapVduse(stateDir string, volName string, ctxVars map[string]string, readon
err = os.WriteFile(stateFile, stateJSON, 0600) err = os.WriteFile(stateFile, stateJSON, 0600)
if (err == nil) if (err == nil)
{ {
klog.Infof("Attached volume %s via VDUSE as %s (VDPA ID %s)", volName, blockdev, vdpaId)
return blockdev, vdpaId, nil return blockdev, vdpaId, nil
} }
} }
@ -308,35 +299,3 @@ func unmapVduseById(stateDir, vdpaId string)
os.Remove(pidFile) os.Remove(pidFile)
} }
} }
func system(program string, args ...string) ([]byte, []byte, error)
{
klog.Infof("Running "+program+" "+strings.Join(args, " "))
c := exec.Command(program, args...)
var stdout, stderr bytes.Buffer
c.Stdout, c.Stderr = &stdout, &stderr
err := c.Run()
if (err != nil)
{
stdoutStr, stderrStr := string(stdout.Bytes()), string(stderr.Bytes())
klog.Errorf(program+" "+strings.Join(args, " ")+" failed: %s\nOutput:\n%s", err, stdoutStr+stderrStr)
return nil, nil, status.Error(codes.Internal, stdoutStr+stderrStr+" (status "+err.Error()+")")
}
return stdout.Bytes(), stderr.Bytes(), nil
}
func systemCombined(program string, args ...string) ([]byte, error)
{
klog.Infof("Running "+program+" "+strings.Join(args, " "))
c := exec.Command(program, args...)
var out bytes.Buffer
c.Stdout, c.Stderr = &out, &out
err := c.Run()
if (err != nil)
{
outStr := string(out.Bytes())
klog.Errorf(program+" "+strings.Join(args, " ")+" failed: %s, status %s\n", outStr, err)
return nil, status.Error(codes.Internal, outStr+" (status "+err.Error()+")")
}
return out.Bytes(), nil
}

2
debian/changelog vendored
View File

@ -1,4 +1,4 @@
vitastor (1.9.3-1) unstable; urgency=medium vitastor (1.7.1-1) unstable; urgency=medium
* Bugfixes * Bugfixes

6
debian/control vendored
View File

@ -53,9 +53,3 @@ Architecture: amd64
Depends: ${shlibs:Depends}, ${misc:Depends}, vitastor-client (= ${binary:Version}) Depends: ${shlibs:Depends}, ${misc:Depends}, vitastor-client (= ${binary:Version})
Description: Vitastor Proxmox Virtual Environment storage plugin Description: Vitastor Proxmox Virtual Environment storage plugin
Vitastor storage plugin for Proxmox Virtual Environment. Vitastor storage plugin for Proxmox Virtual Environment.
Package: vitastor-opennebula
Architecture: amd64
Depends: ${shlibs:Depends}, ${misc:Depends}, vitastor-client, patch, python3, jq
Description: Vitastor OpenNebula storage plugin
Vitastor storage plugin for OpenNebula.

View File

@ -1,3 +0,0 @@
opennebula/remotes var/lib/one/
opennebula/sudoers.d etc/
opennebula/install.sh var/lib/one/remotes/datastore/vitastor/

View File

@ -1,7 +0,0 @@
#!/bin/sh
set -e
if [ "$1" = "configure" ]; then
/var/lib/one/remotes/datastore/vitastor/install.sh
fi

View File

@ -1,4 +0,0 @@
interest /var/lib/one/remotes/datastore/downloader.sh
interest /etc/one/oned.conf
interest /etc/one/vmm_exec/vmm_execrc
interest /etc/apparmor.d/local/abstractions/libvirt-qemu

View File

@ -106,8 +106,8 @@ SSD cache or "media-cache" - for example, a lot of Seagate EXOS drives have
it (they have internal SSD cache even though it's not stated in datasheets). it (they have internal SSD cache even though it's not stated in datasheets).
Setting this parameter to "all" or "small" in OSD parameters requires enabling Setting this parameter to "all" or "small" in OSD parameters requires enabling
[disable_journal_fsync](layout-osd.en.md#disable_journal_fsync) and [disable_journal_fsync](layout-osd.en.yml#disable_journal_fsync) and
[disable_meta_fsync](layout-osd.en.md#disable_meta_fsync), setting it to [disable_meta_fsync](layout-osd.en.yml#disable_meta_fsync), setting it to
"all" also requires enabling [disable_data_fsync](layout-osd.en.md#disable_data_fsync). "all" also requires enabling [disable_data_fsync](layout-osd.en.yml#disable_data_fsync).
vitastor-disk tried to do that by default, first checking/disabling drive cache. vitastor-disk tried to do that by default, first checking/disabling drive cache.
If it can't disable drive cache, OSD get initialized with "none". If it can't disable drive cache, OSD get initialized with "none".

View File

@ -112,6 +112,6 @@ HDD-дисках с внутренним SSD или "медиа" кэшем - н
указано в спецификациях). указано в спецификациях).
Указание "all" или "small" в настройках / командной строке OSD требует Указание "all" или "small" в настройках / командной строке OSD требует
включения [disable_journal_fsync](layout-osd.ru.md#disable_journal_fsync) и включения [disable_journal_fsync](layout-osd.ru.yml#disable_journal_fsync) и
[disable_meta_fsync](layout-osd.ru.md#disable_meta_fsync), значение "all" [disable_meta_fsync](layout-osd.ru.yml#disable_meta_fsync), значение "all"
также требует включения [disable_data_fsync](layout-osd.ru.md#disable_data_fsync). также требует включения [disable_data_fsync](layout-osd.ru.yml#disable_data_fsync).

View File

@ -118,13 +118,12 @@ Physical block size of the journal device. Must be a multiple of
- Type: boolean - Type: boolean
- Default: false - Default: false
Do not issue fsyncs to the data device, i.e. do not force it to flush cache. Do not issue fsyncs to the data device, i.e. do not flush its cache.
Safe ONLY if your data device has write-through cache or if write-back Safe ONLY if your data device has write-through cache. If you disable
cache is disabled. If you disable drive cache manually with `hdparm` or the cache yourself using `hdparm` or `scsi_disk/cache_type` then make sure
writing to `/sys/.../scsi_disk/cache_type` then make sure that you do it that the cache disable command is run every time before starting Vitastor
every time before starting Vitastor OSD (vitastor-disk does it automatically). OSD, for example, in the systemd unit. See also `immediate_commit` option
See also [immediate_commit](layout-cluster.en.md#immediate_commit) for the instructions to disable cache and how to benefit from it.
for information about how to benefit from disabled cache.
## disable_meta_fsync ## disable_meta_fsync
@ -172,7 +171,8 @@ size, it actually has to write the whole 4 KB sector.
Because of this it can actually be beneficial to use SSDs which work well Because of this it can actually be beneficial to use SSDs which work well
with 512 byte sectors and use 512 byte disk_alignment, journal_block_size with 512 byte sectors and use 512 byte disk_alignment, journal_block_size
and meta_block_size. But at the moment, no such SSDs are known... and meta_block_size. But the only SSD that may fit into this category is
Intel Optane (probably, not tested yet).
Clients don't need to be aware of disk_alignment, so it's not required to Clients don't need to be aware of disk_alignment, so it's not required to
put a modified value into etcd key /vitastor/config/global. put a modified value into etcd key /vitastor/config/global.

View File

@ -122,14 +122,13 @@ SSD-диске, иначе производительность пострада
- Тип: булево (да/нет) - Тип: булево (да/нет)
- Значение по умолчанию: false - Значение по умолчанию: false
Не отправлять fsync-и устройству данных, т.е. не заставлять его сбрасывать кэш. Не отправлять fsync-и устройству данных, т.е. не сбрасывать его кэш.
Безопасно, ТОЛЬКО если ваше устройство данных имеет кэш со сквозной Безопасно, ТОЛЬКО если ваше устройство данных имеет кэш со сквозной
записью (write-through) или если кэш с отложенной записью (write-back) отключён. записью (write-through). Если вы отключаете кэш через `hdparm` или
Если вы отключаете кэш вручную через `hdparm` или запись в `/sys/.../scsi_disk/cache_type`, `scsi_disk/cache_type`, то удостоверьтесь, что команда отключения кэша
то удостоверьтесь, что вы делаете это каждый раз перед запуском Vitastor OSD выполняется перед каждым запуском Vitastor OSD, например, в systemd unit-е.
(vitastor-disk делает это автоматически). Смотрите также опцию Смотрите также опцию `immediate_commit` для инструкций по отключению кэша
[immediate_commit](layout-cluster.ru.md#immediate_commit) для информации о том, и о том, как из этого извлечь выгоду.
как извлечь выгоду из отключённого кэша.
## disable_meta_fsync ## disable_meta_fsync
@ -180,8 +179,9 @@ SSD и HDD диски используют 4 КБ физические сект
Поэтому, на самом деле, может быть выгодно найти SSD, хорошо работающие с Поэтому, на самом деле, может быть выгодно найти SSD, хорошо работающие с
меньшими, 512-байтными, блоками и использовать 512-байтные disk_alignment, меньшими, 512-байтными, блоками и использовать 512-байтные disk_alignment,
journal_block_size и meta_block_size. Однако на данный момент такие SSD journal_block_size и meta_block_size. Однако единственные SSD, которые
не известны... теоретически могут попасть в эту категорию - это Intel Optane (но и это
пока не проверялось автором).
Клиентам не обязательно знать про disk_alignment, так что помещать значение Клиентам не обязательно знать про disk_alignment, так что помещать значение
этого параметра в etcd в /vitastor/config/global не нужно. этого параметра в etcd в /vitastor/config/global не нужно.

View File

@ -68,17 +68,11 @@ but they are not connected to the cluster.
- Type: string - Type: string
RDMA device name to use for Vitastor OSD communications (for example, RDMA device name to use for Vitastor OSD communications (for example,
"rocep5s0f0"). If not specified, Vitastor will try to find an RoCE "rocep5s0f0"). Now Vitastor supports all adapters, even ones without
device matching [osd_network](osd.en.md#osd_network), preferring RoCEv2, ODP support, like Mellanox ConnectX-3 and non-Mellanox cards.
or choose the first available RDMA device if no RoCE devices are
found or if `osd_network` is not specified. Auto-selection is also
unsupported with old libibverbs < v32, like in Debian 10 Buster or
CentOS 7.
Vitastor supports all adapters, even ones without ODP support, like Versions up to Vitastor 1.2.0 required ODP which is only present in
Mellanox ConnectX-3 and non-Mellanox cards. Versions up to Vitastor Mellanox ConnectX >= 4. See also [rdma_odp](#rdma_odp).
1.2.0 required ODP which is only present in Mellanox ConnectX >= 4.
See also [rdma_odp](#rdma_odp).
Run `ibv_devinfo -v` as root to list available RDMA devices and their Run `ibv_devinfo -v` as root to list available RDMA devices and their
features. features.
@ -101,17 +95,15 @@ your device has.
## rdma_gid_index ## rdma_gid_index
- Type: integer - Type: integer
- Default: 0
Global address identifier index of the RDMA device to use. Different GID Global address identifier index of the RDMA device to use. Different GID
indexes may correspond to different protocols like RoCEv1, RoCEv2 and iWARP. indexes may correspond to different protocols like RoCEv1, RoCEv2 and iWARP.
Search for "GID" in `ibv_devinfo -v` output to determine which GID index Search for "GID" in `ibv_devinfo -v` output to determine which GID index
you need. you need.
If not specified, Vitastor will try to auto-select a RoCEv2 IPv4 GID, then **IMPORTANT:** If you want to use RoCEv2 (as recommended) then the correct
RoCEv2 IPv6 GID, then RoCEv1 IPv4 GID, then RoCEv1 IPv6 GID, then IB GID. rdma_gid_index is usually 1 (IPv6) or 3 (IPv4).
GID auto-selection is unsupported with libibverbs < v32.
A correct rdma_gid_index for RoCEv2 is usually 1 (IPv6) or 3 (IPv4).
## rdma_mtu ## rdma_mtu

View File

@ -71,17 +71,12 @@ RDMA может быть нужно только если у клиентов е
- Тип: строка - Тип: строка
Название RDMA-устройства для связи с Vitastor OSD (например, "rocep5s0f0"). Название RDMA-устройства для связи с Vitastor OSD (например, "rocep5s0f0").
Если не указано, Vitastor попробует найти RoCE-устройство, соответствующее Сейчас Vitastor поддерживает все модели адаптеров, включая те, у которых
[osd_network](osd.en.md#osd_network), предпочитая RoCEv2, или выбрать первое
попавшееся RDMA-устройство, если RoCE-устройств нет или если сеть `osd_network`
не задана. Также автовыбор не поддерживается со старыми версиями библиотеки
libibverbs < v32, например в Debian 10 Buster или CentOS 7.
Vitastor поддерживает все модели адаптеров, включая те, у которых
нет поддержки ODP, то есть вы можете использовать RDMA с ConnectX-3 и нет поддержки ODP, то есть вы можете использовать RDMA с ConnectX-3 и
картами производства не Mellanox. Версии Vitastor до 1.2.0 включительно картами производства не Mellanox.
требовали ODP, который есть только на Mellanox ConnectX 4 и более новых.
См. также [rdma_odp](#rdma_odp). Версии Vitastor до 1.2.0 включительно требовали ODP, который есть только
на Mellanox ConnectX 4 и более новых. См. также [rdma_odp](#rdma_odp).
Запустите `ibv_devinfo -v` от имени суперпользователя, чтобы посмотреть Запустите `ibv_devinfo -v` от имени суперпользователя, чтобы посмотреть
список доступных RDMA-устройств, их параметры и возможности. список доступных RDMA-устройств, их параметры и возможности.
@ -106,18 +101,15 @@ Control) и ECN (Explicit Congestion Notification).
## rdma_gid_index ## rdma_gid_index
- Тип: целое число - Тип: целое число
- Значение по умолчанию: 0
Номер глобального идентификатора адреса RDMA-устройства, который следует Номер глобального идентификатора адреса RDMA-устройства, который следует
использовать. Разным gid_index могут соответствовать разные протоколы связи: использовать. Разным gid_index могут соответствовать разные протоколы связи:
RoCEv1, RoCEv2, iWARP. Чтобы понять, какой нужен вам - смотрите строчки со RoCEv1, RoCEv2, iWARP. Чтобы понять, какой нужен вам - смотрите строчки со
словом "GID" в выводе команды `ibv_devinfo -v`. словом "GID" в выводе команды `ibv_devinfo -v`.
Если не указан, Vitastor попробует автоматически выбрать сначала GID, **ВАЖНО:** Если вы хотите использовать RoCEv2 (как мы и рекомендуем), то
соответствующий RoCEv2 IPv4, потом RoCEv2 IPv6, потом RoCEv1 IPv4, потом правильный rdma_gid_index, как правило, 1 (IPv6) или 3 (IPv4).
RoCEv1 IPv6, потом IB. Авто-выбор GID не поддерживается со старыми версиями
libibverbs < v32.
Правильный rdma_gid_index для RoCEv2, как правило, 1 (IPv6) или 3 (IPv4).
## rdma_mtu ## rdma_mtu

View File

@ -55,7 +55,7 @@ Examples:
OSD placement tree is set in a separate etcd key `/vitastor/config/node_placement` OSD placement tree is set in a separate etcd key `/vitastor/config/node_placement`
in the following JSON format: in the following JSON format:
``` `
{ {
"<node name or OSD number>": { "<node name or OSD number>": {
"level": "<level>", "level": "<level>",
@ -63,7 +63,7 @@ in the following JSON format:
}, },
... ...
} }
``` `
Here, if a node name is a number then it is assumed to refer to an OSD. Here, if a node name is a number then it is assumed to refer to an OSD.
Level of the OSD is always "osd" and cannot be overriden. You may only Level of the OSD is always "osd" and cannot be overriden. You may only

View File

@ -54,7 +54,7 @@
Дерево размещения OSD задаётся в отдельном ключе etcd `/vitastor/config/node_placement` Дерево размещения OSD задаётся в отдельном ключе etcd `/vitastor/config/node_placement`
в следующем JSON-формате: в следующем JSON-формате:
``` `
{ {
"<имя узла или номер OSD>": { "<имя узла или номер OSD>": {
"level": "<уровень>", "level": "<уровень>",
@ -62,7 +62,7 @@
}, },
... ...
} }
``` `
Здесь, если название узла - число, считается, что это OSD. Уровень OSD Здесь, если название узла - число, считается, что это OSD. Уровень OSD
всегда равен "osd" и не может быть переопределён. Для OSD вы можете только всегда равен "osd" и не может быть переопределён. Для OSD вы можете только

View File

@ -97,9 +97,9 @@
it (they have internal SSD cache even though it's not stated in datasheets). it (they have internal SSD cache even though it's not stated in datasheets).
Setting this parameter to "all" or "small" in OSD parameters requires enabling Setting this parameter to "all" or "small" in OSD parameters requires enabling
[disable_journal_fsync](layout-osd.en.md#disable_journal_fsync) and [disable_journal_fsync](layout-osd.en.yml#disable_journal_fsync) and
[disable_meta_fsync](layout-osd.en.md#disable_meta_fsync), setting it to [disable_meta_fsync](layout-osd.en.yml#disable_meta_fsync), setting it to
"all" also requires enabling [disable_data_fsync](layout-osd.en.md#disable_data_fsync). "all" also requires enabling [disable_data_fsync](layout-osd.en.yml#disable_data_fsync).
vitastor-disk tried to do that by default, first checking/disabling drive cache. vitastor-disk tried to do that by default, first checking/disabling drive cache.
If it can't disable drive cache, OSD get initialized with "none". If it can't disable drive cache, OSD get initialized with "none".
info_ru: | info_ru: |
@ -156,6 +156,6 @@
указано в спецификациях). указано в спецификациях).
Указание "all" или "small" в настройках / командной строке OSD требует Указание "all" или "small" в настройках / командной строке OSD требует
включения [disable_journal_fsync](layout-osd.ru.md#disable_journal_fsync) и включения [disable_journal_fsync](layout-osd.ru.yml#disable_journal_fsync) и
[disable_meta_fsync](layout-osd.ru.md#disable_meta_fsync), значение "all" [disable_meta_fsync](layout-osd.ru.yml#disable_meta_fsync), значение "all"
также требует включения [disable_data_fsync](layout-osd.ru.md#disable_data_fsync). также требует включения [disable_data_fsync](layout-osd.ru.yml#disable_data_fsync).

View File

@ -110,22 +110,20 @@
type: bool type: bool
default: false default: false
info: | info: |
Do not issue fsyncs to the data device, i.e. do not force it to flush cache. Do not issue fsyncs to the data device, i.e. do not flush its cache.
Safe ONLY if your data device has write-through cache or if write-back Safe ONLY if your data device has write-through cache. If you disable
cache is disabled. If you disable drive cache manually with `hdparm` or the cache yourself using `hdparm` or `scsi_disk/cache_type` then make sure
writing to `/sys/.../scsi_disk/cache_type` then make sure that you do it that the cache disable command is run every time before starting Vitastor
every time before starting Vitastor OSD (vitastor-disk does it automatically). OSD, for example, in the systemd unit. See also `immediate_commit` option
See also [immediate_commit](layout-cluster.en.md#immediate_commit) for the instructions to disable cache and how to benefit from it.
for information about how to benefit from disabled cache.
info_ru: | info_ru: |
Не отправлять fsync-и устройству данных, т.е. не заставлять его сбрасывать кэш. Не отправлять fsync-и устройству данных, т.е. не сбрасывать его кэш.
Безопасно, ТОЛЬКО если ваше устройство данных имеет кэш со сквозной Безопасно, ТОЛЬКО если ваше устройство данных имеет кэш со сквозной
записью (write-through) или если кэш с отложенной записью (write-back) отключён. записью (write-through). Если вы отключаете кэш через `hdparm` или
Если вы отключаете кэш вручную через `hdparm` или запись в `/sys/.../scsi_disk/cache_type`, `scsi_disk/cache_type`, то удостоверьтесь, что команда отключения кэша
то удостоверьтесь, что вы делаете это каждый раз перед запуском Vitastor OSD выполняется перед каждым запуском Vitastor OSD, например, в systemd unit-е.
(vitastor-disk делает это автоматически). Смотрите также опцию Смотрите также опцию `immediate_commit` для инструкций по отключению кэша
[immediate_commit](layout-cluster.ru.md#immediate_commit) для информации о том, и о том, как из этого извлечь выгоду.
как извлечь выгоду из отключённого кэша.
- name: disable_meta_fsync - name: disable_meta_fsync
type: bool type: bool
default: false default: false
@ -181,7 +179,8 @@
Because of this it can actually be beneficial to use SSDs which work well Because of this it can actually be beneficial to use SSDs which work well
with 512 byte sectors and use 512 byte disk_alignment, journal_block_size with 512 byte sectors and use 512 byte disk_alignment, journal_block_size
and meta_block_size. But at the moment, no such SSDs are known... and meta_block_size. But the only SSD that may fit into this category is
Intel Optane (probably, not tested yet).
Clients don't need to be aware of disk_alignment, so it's not required to Clients don't need to be aware of disk_alignment, so it's not required to
put a modified value into etcd key /vitastor/config/global. put a modified value into etcd key /vitastor/config/global.
@ -199,8 +198,9 @@
Поэтому, на самом деле, может быть выгодно найти SSD, хорошо работающие с Поэтому, на самом деле, может быть выгодно найти SSD, хорошо работающие с
меньшими, 512-байтными, блоками и использовать 512-байтные disk_alignment, меньшими, 512-байтными, блоками и использовать 512-байтные disk_alignment,
journal_block_size и meta_block_size. Однако на данный момент такие SSD journal_block_size и meta_block_size. Однако единственные SSD, которые
не известны... теоретически могут попасть в эту категорию - это Intel Optane (но и это
пока не проверялось автором).
Клиентам не обязательно знать про disk_alignment, так что помещать значение Клиентам не обязательно знать про disk_alignment, так что помещать значение
этого параметра в etcd в /vitastor/config/global не нужно. этого параметра в etcd в /vitastor/config/global не нужно.

View File

@ -48,17 +48,11 @@
type: string type: string
info: | info: |
RDMA device name to use for Vitastor OSD communications (for example, RDMA device name to use for Vitastor OSD communications (for example,
"rocep5s0f0"). If not specified, Vitastor will try to find an RoCE "rocep5s0f0"). Now Vitastor supports all adapters, even ones without
device matching [osd_network](osd.en.md#osd_network), preferring RoCEv2, ODP support, like Mellanox ConnectX-3 and non-Mellanox cards.
or choose the first available RDMA device if no RoCE devices are
found or if `osd_network` is not specified. Auto-selection is also
unsupported with old libibverbs < v32, like in Debian 10 Buster or
CentOS 7.
Vitastor supports all adapters, even ones without ODP support, like Versions up to Vitastor 1.2.0 required ODP which is only present in
Mellanox ConnectX-3 and non-Mellanox cards. Versions up to Vitastor Mellanox ConnectX >= 4. See also [rdma_odp](#rdma_odp).
1.2.0 required ODP which is only present in Mellanox ConnectX >= 4.
See also [rdma_odp](#rdma_odp).
Run `ibv_devinfo -v` as root to list available RDMA devices and their Run `ibv_devinfo -v` as root to list available RDMA devices and their
features. features.
@ -70,17 +64,12 @@
PFC (Priority Flow Control) and ECN (Explicit Congestion Notification). PFC (Priority Flow Control) and ECN (Explicit Congestion Notification).
info_ru: | info_ru: |
Название RDMA-устройства для связи с Vitastor OSD (например, "rocep5s0f0"). Название RDMA-устройства для связи с Vitastor OSD (например, "rocep5s0f0").
Если не указано, Vitastor попробует найти RoCE-устройство, соответствующее Сейчас Vitastor поддерживает все модели адаптеров, включая те, у которых
[osd_network](osd.en.md#osd_network), предпочитая RoCEv2, или выбрать первое
попавшееся RDMA-устройство, если RoCE-устройств нет или если сеть `osd_network`
не задана. Также автовыбор не поддерживается со старыми версиями библиотеки
libibverbs < v32, например в Debian 10 Buster или CentOS 7.
Vitastor поддерживает все модели адаптеров, включая те, у которых
нет поддержки ODP, то есть вы можете использовать RDMA с ConnectX-3 и нет поддержки ODP, то есть вы можете использовать RDMA с ConnectX-3 и
картами производства не Mellanox. Версии Vitastor до 1.2.0 включительно картами производства не Mellanox.
требовали ODP, который есть только на Mellanox ConnectX 4 и более новых.
См. также [rdma_odp](#rdma_odp). Версии Vitastor до 1.2.0 включительно требовали ODP, который есть только
на Mellanox ConnectX 4 и более новых. См. также [rdma_odp](#rdma_odp).
Запустите `ibv_devinfo -v` от имени суперпользователя, чтобы посмотреть Запустите `ibv_devinfo -v` от имени суперпользователя, чтобы посмотреть
список доступных RDMA-устройств, их параметры и возможности. список доступных RDMA-устройств, их параметры и возможности.
@ -105,29 +94,23 @@
`ibv_devinfo -v`. `ibv_devinfo -v`.
- name: rdma_gid_index - name: rdma_gid_index
type: int type: int
default: 0
info: | info: |
Global address identifier index of the RDMA device to use. Different GID Global address identifier index of the RDMA device to use. Different GID
indexes may correspond to different protocols like RoCEv1, RoCEv2 and iWARP. indexes may correspond to different protocols like RoCEv1, RoCEv2 and iWARP.
Search for "GID" in `ibv_devinfo -v` output to determine which GID index Search for "GID" in `ibv_devinfo -v` output to determine which GID index
you need. you need.
If not specified, Vitastor will try to auto-select a RoCEv2 IPv4 GID, then **IMPORTANT:** If you want to use RoCEv2 (as recommended) then the correct
RoCEv2 IPv6 GID, then RoCEv1 IPv4 GID, then RoCEv1 IPv6 GID, then IB GID. rdma_gid_index is usually 1 (IPv6) or 3 (IPv4).
GID auto-selection is unsupported with libibverbs < v32.
A correct rdma_gid_index for RoCEv2 is usually 1 (IPv6) or 3 (IPv4).
info_ru: | info_ru: |
Номер глобального идентификатора адреса RDMA-устройства, который следует Номер глобального идентификатора адреса RDMA-устройства, который следует
использовать. Разным gid_index могут соответствовать разные протоколы связи: использовать. Разным gid_index могут соответствовать разные протоколы связи:
RoCEv1, RoCEv2, iWARP. Чтобы понять, какой нужен вам - смотрите строчки со RoCEv1, RoCEv2, iWARP. Чтобы понять, какой нужен вам - смотрите строчки со
словом "GID" в выводе команды `ibv_devinfo -v`. словом "GID" в выводе команды `ibv_devinfo -v`.
Если не указан, Vitastor попробует автоматически выбрать сначала GID, **ВАЖНО:** Если вы хотите использовать RoCEv2 (как мы и рекомендуем), то
соответствующий RoCEv2 IPv4, потом RoCEv2 IPv6, потом RoCEv1 IPv4, потом правильный rdma_gid_index, как правило, 1 (IPv6) или 3 (IPv4).
RoCEv1 IPv6, потом IB. Авто-выбор GID не поддерживается со старыми версиями
libibverbs < v32.
Правильный rdma_gid_index для RoCEv2, как правило, 1 (IPv6) или 3 (IPv4).
- name: rdma_mtu - name: rdma_mtu
type: int type: int
default: 4096 default: 4096

View File

@ -1,186 +0,0 @@
[Documentation](../../README.md#documentation) → Installation → OpenNebula
-----
[Читать на русском](opennebula.ru.md)
# OpenNebula
## Automatic Installation
OpenNebula plugin is packaged as `vitastor-opennebula` Debian and RPM package since Vitastor 1.9.0. So:
- Run `apt-get install vitastor-opennebula` or `yum install vitastor-opennebula` after installing OpenNebula on all nodes
- Check that it prints "OK, Vitastor OpenNebula patches successfully applied" or "OK, Vitastor OpenNebula patches are already applied"
- If it does not, refer to [Manual Installation](#manual-installation) and apply configuration file changes manually
- Make sure that Vitastor patched versions of QEMU and libvirt are installed
(`dpkg -l qemu-system-x86`, `dpkg -l | grep libvirt`, `rpm -qa | grep qemu`, `rpm -qa | grep qemu`, `rpm -qa | grep libvirt-libs` should show "vitastor" in version names)
- [Block VM access to Vitastor cluster](#block-vm-access-to-vitastor-cluster)
## Manual Installation
Install OpenNebula. Then, on each node:
- Copy [opennebula/remotes](../../opennebula/remotes) into `/var/lib/one` recursively: `cp -r opennebula/remotes /var/lib/one/`
- Copy [opennebula/sudoers.d](../../opennebula/sudoers.d) to `/etc`: `cp -r opennebula/sudoers.d /etc/`
- Apply [downloader-vitastor.sh.diff](../../opennebula/remotes/datastore/vitastor/downloader-vitastor.sh.diff) to `/var/lib/one/remotes/datastore/downloader.sh`:
`patch /var/lib/one/remotes/datastore/downloader.sh < opennebula/remotes/datastore/vitastor/downloader-vitastor.sh.diff` - or read the patch and apply the same change manually
- Add `kvm-vitastor` to `LIVE_DISK_SNAPSHOTS` in `/etc/one/vmm_exec/vmm_execrc`
- If on Debian or Ubuntu (and AppArmor is used), add Vitastor config file path(s) to `/etc/apparmor.d/local/abstractions/libvirt-qemu`: for example,
`echo ' "/etc/vitastor/vitastor.conf" r,' >> /etc/apparmor.d/local/abstractions/libvirt-qemu`
- Apply changes to `/etc/one/oned.conf`
### oned.conf changes
1. Add deploy script override in kvm VM_MAD: add `-l deploy.vitastor` to ARGUMENTS.
```diff
VM_MAD = [
NAME = "kvm",
SUNSTONE_NAME = "KVM",
EXECUTABLE = "one_vmm_exec",
- ARGUMENTS = "-t 15 -r 0 kvm -p",
+ ARGUMENTS = "-t 15 -r 0 kvm -p -l deploy=deploy.vitastor",
DEFAULT = "vmm_exec/vmm_exec_kvm.conf",
TYPE = "kvm",
KEEP_SNAPSHOTS = "yes",
LIVE_RESIZE = "yes",
SUPPORT_SHAREABLE = "yes",
IMPORTED_VMS_ACTIONS = "terminate, terminate-hard, hold, release, suspend,
resume, delete, reboot, reboot-hard, resched, unresched, disk-attach,
disk-detach, nic-attach, nic-detach, snapshot-create, snapshot-delete,
resize, updateconf, update"
]
```
Optional: if you also want to save VM RAM checkpoints to Vitastor, use
`-l deploy=deploy.vitastor,save=save.vitastor,restore=restore.vitastor`
instead of just `-l deploy=deploy.vitastor`.
2. Add `vitastor` to TM_MAD.ARGUMENTS and DATASTORE_MAD.ARGUMENTS:
```diff
TM_MAD = [
EXECUTABLE = "one_tm",
- ARGUMENTS = "-t 15 -d dummy,lvm,shared,fs_lvm,fs_lvm_ssh,qcow2,ssh,ceph,dev,vcenter,iscsi_libvirt"
+ ARGUMENTS = "-t 15 -d dummy,lvm,shared,fs_lvm,fs_lvm_ssh,qcow2,ssh,ceph,vitastor,dev,vcenter,iscsi_libvirt"
]
DATASTORE_MAD = [
EXECUTABLE = "one_datastore",
- ARGUMENTS = "-t 15 -d dummy,fs,lvm,ceph,dev,iscsi_libvirt,vcenter,restic,rsync -s shared,ssh,ceph,fs_lvm,fs_lvm_ssh,qcow2,vcenter"
+ ARGUMENTS = "-t 15 -d dummy,fs,lvm,ceph,vitastor,dev,iscsi_libvirt,vcenter,restic,rsync -s shared,ssh,ceph,vitastor,fs_lvm,fs_lvm_ssh,qcow2,vcenter"
]
```
3. Add INHERIT_DATASTORE_ATTR for two Vitastor attributes:
```
INHERIT_DATASTORE_ATTR = "VITASTOR_CONF"
INHERIT_DATASTORE_ATTR = "IMAGE_PREFIX"
```
4. Add TM_MAD_CONF and DS_MAD_CONF for Vitastor:
```
TM_MAD_CONF = [
NAME = "vitastor", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES",
DS_MIGRATE = "NO", DRIVER = "raw", ALLOW_ORPHANS="format",
TM_MAD_SYSTEM = "ssh,shared", LN_TARGET_SSH = "SYSTEM", CLONE_TARGET_SSH = "SYSTEM",
DISK_TYPE_SSH = "FILE", LN_TARGET_SHARED = "NONE",
CLONE_TARGET_SHARED = "SELF", DISK_TYPE_SHARED = "FILE"
]
DS_MAD_CONF = [
NAME = "vitastor",
REQUIRED_ATTRS = "DISK_TYPE,BRIDGE_LIST",
PERSISTENT_ONLY = "NO",
MARKETPLACE_ACTIONS = "export"
]
```
## Create Datastores
Example Image and System Datastore definitions:
[opennebula/vitastor-imageds.conf](../../opennebula/vitastor-imageds.conf) and
[opennebula/vitastor-systemds.conf](../../opennebula/vitastor-systemds.conf).
Change parameters to your will:
- POOL_NAME is Vitastor pool name to store images.
- IMAGE_PREFIX is a string prepended to all Vitastor image names.
- BRIDGE_LIST is a list of hosts with access to Vitastor cluster, mostly used for image (not system) datastore operations.
- VITASTOR_CONF is the path to cluster configuration. Note that it should be also added to `/etc/apparmor.d/local/abstractions/libvirt-qemu` if you use AppArmor.
- STAGING_DIR is a temporary directory used when importing external images. Should have free space sufficient for downloading external images.
Then create datastores using `onedatastore create vitastor-imageds.conf` and `onedatastore create vitastor-systemds.conf` (or use UI).
## Block VM access to Vitastor cluster
Vitastor doesn't support any authentication yet, so you MUST block VM guest access to the Vitastor cluster at the network level.
If you use VLAN networking for VMs - make sure you use different VLANs for VMs and hypervisor/storage network and
block access between them using your firewall/switch configuration.
If you use something more stupid like bridged networking, you probably have to use manual firewall/iptables setup
to only allow access to Vitastor from hypervisor IPs.
Also you need to switch network to "Bridged & Security Groups" and enable IP spoofing filters in OpenNebula.
Problem is that OpenNebula's IP spoofing filter doesn't affect local interfaces of the hypervisor i.e. when
it's enabled a VM can't talk to other VMs or to the outer world using a spoofed IP, but it CAN talk to the
hypervisor if it takes an IP from its subnet. To fix that you also need some more iptables.
So the complete "stupid" bridged network filter setup could look like the following
(here `10.0.3.0/24` is the VM subnet and `10.0.2.0/24` is the hypervisor subnet):
```
# Allow incoming traffic from physical device
iptables -A INPUT -m physdev --physdev-in eth0 -j ACCEPT
# Do not allow incoming traffic from VMs, but not from VM subnet
iptables -A INPUT ! -s 10.0.3.0/24 -i onebr0 -j DROP
# Drop traffic from VMs to hypervisor/storage subnet
iptables -I FORWARD 1 -s 10.0.3.0/24 -d 10.0.2.0/24 -j DROP
```
## Testing
The OpenNebula plugin includes quite a bit of bash scripts, so here's their description to get an idea about what they actually do.
| Script | Action | How to Test |
| ----------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------ |
| vmm/kvm/deploy.vitastor | Start a VM | Create and start a VM with Vitastor disk(s): persistent / non-persistent / volatile. |
| vmm/kvm/save.vitastor | Save VM memory checkpoint | Stop a VM using "Stop" command. |
| vmm/kvm/restore.vitastor| Restore VM memory checkpoint | Start a VM back after stopping it. |
| datastore/clone | Copy an image as persistent | Create a VM template and instantiate it as persistent. |
| datastore/cp | Import an external image | Import a VM template with images from Marketplace. |
| datastore/export | Export an image as URL | Probably: export a VM template with images to Marketplace. |
| datastore/mkfs | Create an image with FS | Storage → Images → Create → Type: Datablock, Location: Empty disk image, Filesystem: Not empty. |
| datastore/monitor | Monitor used space in image datastore | Check reported used/free space in image datastore list. |
| datastore/rm | Remove a persistent image | Storage → Images → Select an image → Delete. |
| datastore/snap_delete | Delete a snapshot of a persistent image | Storage → Images → Select an image → Select a snapshot → Delete; <br> To create an image with snapshot: attach a persistent image to a VM; create a snapshot; detach the image. |
| datastore/snap_flatten | Revert an image to snapshot and delete other snapshots | Storage → Images → Select an image → Select a snapshot → Flatten. |
| datastore/snap_revert | Revert an image to snapshot | Storage → Images → Select an image → Select a snapshot → Revert. |
| datastore/stat | Get virtual size of an image in MB | No idea. Seems to be unused both in Vitastor and Ceph datastores. |
| tm/clone | Clone a non-persistent image to a VM disk | Attach a non-persistent image to a VM. |
| tm/context | Generate a contextualisation VM disk | Create a VM with enabled contextualisation (default). Common host FS-based version is used in Vitastor and Ceph datastores. |
| tm/cpds | Copy a VM disk / its snapshot to an image | Select a VM → Select a disk → Optionally select a snapshot → Save as. |
| tm/delete | Delete a cloned or volatile VM disk | Detach a volatile disk or a non-persistent image from a VM. |
| tm/failmigrate | Handle live migration failure | No action. Script is empty in Vitastor and Ceph. In other datastores, should roll back actions done by tm/premigrate. |
| tm/ln | Attach a persistent image to a VM | No action. Script is empty in Vitastor and Ceph. |
| tm/mkimage | Create a volatile disk, maybe with FS | Attach a volatile disk to a VM, with or without file system. |
| tm/mkswap | Create a volatile swap disk | Attach a volatile disk to a VM, formatted as swap. |
| tm/monitor | Monitor used space in system datastore | Check reported used/free space in system datastore list. |
| tm/mv | Move a migrated VM disk between hosts | Migrate a VM between hosts. In Vitastor and Ceph datastores, doesn't do any storage action. |
| tm/mvds | Detach a persistent image from a VM | No action. The opposite of tm/ln. Script is empty in Vitastor and Ceph. In other datastores, script may copy the image from VM host back to the datastore. |
| tm/postbackup | Executed after backup | Seems that the script just removes temporary files after backup. Perform a VM backup and check that temporary files are cleaned up. |
| tm/postbackup_live | Executed after backup of a running VM | Same as tm/postbackup, but for a running VM. |
| tm/postmigrate | Executed after VM live migration | No action. Only executed for system datastore, so the script tries to call other TMs for other disks. Except that, the script does nothing in Vitastor and Ceph datastores. |
| tm/prebackup | Actual backup script: backup VM disks | Set up "rsync" backup datastore → Backup a VM to it. |
| tm/prebackup_live | Backup VM disks of a running VM | Same as tm/prebackup, but also does fsfreeze/thaw. So perform a live backup, restore it and check that disks are consistent. |
| tm/premigrate | Executed before live migration | No action. Only executed for system datastore, so the script tries to call other TMs for other disks. Except that, the script does nothing in Vitastor and Ceph datastores. |
| tm/resize | Resize a VM disk | Select a VM → Select a non-persistent disk → Resize. |
| tm/restore | Restore VM disks from backup | Set up "rsync" backup datastore → Backup a VM to it → Restore it back. |
| tm/snap_create | Create a VM disk snapshot | Select a VM → Select a disk → Create snapshot. |
| tm/snap_create_live | Create a VM disk snapshot for a live VM | Select a running VM → Select a disk → Create snapshot. |
| tm/snap_delete | Delete a VM disk snapshot | Select a VM → Select a disk → Select a snapshot → Delete. |
| tm/snap_revert | Revert a VM disk to a snapshot | Select a VM → Select a disk → Select a snapshot → Revert. |

View File

@ -1,189 +0,0 @@
[Документация](../../README-ru.md#документация) → Установка → OpenNebula
-----
[Read in English](opennebula.en.md)
# OpenNebula
## Автоматическая установка
Плагин OpenNebula Vitastor распространяется как Debian и RPM пакет `vitastor-opennebula`, начиная с версии Vitastor 1.9.0. Так что:
- Запустите `apt-get install vitastor-opennebula` или `yum install vitastor-opennebula` после установки OpenNebula на всех серверах
- Проверьте, что он выводит "OK, Vitastor OpenNebula patches successfully applied" или "OK, Vitastor OpenNebula patches are already applied" в процессе установки
- Если сообщение не выведено, пройдите по шагам инструкцию [Ручная установка](#ручная-установка) и примените правки файлов конфигурации вручную
- Удостоверьтесь, что установлены версии QEMU и libvirt с изменениями Vitastor
(`dpkg -l qemu-system-x86`, `dpkg -l | grep libvirt`, `rpm -qa | grep qemu`, `rpm -qa | grep qemu`, `rpm -qa | grep libvirt-libs` должны показывать "vitastor" в номере версии)
- [Заблокируйте доступ виртуальных машин в Vitastor](#блокировка-доступа-вм-в-vitastor)
## Ручная установка
Сначала установите саму OpenNebula. После этого, на каждом сервере:
- Скопируйте директорию [opennebula/remotes](../../opennebula/remotes) в `/var/lib/one`: `cp -r opennebula/remotes /var/lib/one/`
- Скопируйте директорию [opennebula/sudoers.d](../../opennebula/sudoers.d) в `/etc`: `cp -r opennebula/sudoers.d /etc/`
- Примените патч [downloader-vitastor.sh.diff](../../opennebula/remotes/datastore/vitastor/downloader-vitastor.sh.diff) к `/var/lib/one/remotes/datastore/downloader.sh`:
`patch /var/lib/one/remotes/datastore/downloader.sh < opennebula/remotes/datastore/vitastor/downloader-vitastor.sh.diff` - либо прочитайте патч и примените изменение вручную
- Добавьте `kvm-vitastor` в список `LIVE_DISK_SNAPSHOTS` в файле `/etc/one/vmm_exec/vmm_execrc`
- Если вы используете Debian или Ubuntu (и AppArmor), добавьте пути к файлу(ам) конфигурации Vitastor в файл `/etc/apparmor.d/local/abstractions/libvirt-qemu`: например,
`echo ' "/etc/vitastor/vitastor.conf" r,' >> /etc/apparmor.d/local/abstractions/libvirt-qemu`
- Примените изменения `/etc/one/oned.conf`
### Изменения oned.conf
1. Добавьте переопределение скрипта deploy в VM_MAD kvm, добавив `-l deploy.vitastor` в `ARGUMENTS`:
```diff
VM_MAD = [
NAME = "kvm",
SUNSTONE_NAME = "KVM",
EXECUTABLE = "one_vmm_exec",
- ARGUMENTS = "-t 15 -r 0 kvm -p",
+ ARGUMENTS = "-t 15 -r 0 kvm -p -l deploy=deploy.vitastor",
DEFAULT = "vmm_exec/vmm_exec_kvm.conf",
TYPE = "kvm",
KEEP_SNAPSHOTS = "yes",
LIVE_RESIZE = "yes",
SUPPORT_SHAREABLE = "yes",
IMPORTED_VMS_ACTIONS = "terminate, terminate-hard, hold, release, suspend,
resume, delete, reboot, reboot-hard, resched, unresched, disk-attach,
disk-detach, nic-attach, nic-detach, snapshot-create, snapshot-delete,
resize, updateconf, update"
]
```
Опционально: если вы хотите также сохранять снимки памяти ВМ в Vitastor, добавьте
`-l deploy=deploy.vitastor,save=save.vitastor,restore=restore.vitastor`
вместо просто `-l deploy=deploy.vitastor`.
2. Добавьте `vitastor` в значения TM_MAD.ARGUMENTS и DATASTORE_MAD.ARGUMENTS:
```diff
TM_MAD = [
EXECUTABLE = "one_tm",
- ARGUMENTS = "-t 15 -d dummy,lvm,shared,fs_lvm,fs_lvm_ssh,qcow2,ssh,ceph,dev,vcenter,iscsi_libvirt"
+ ARGUMENTS = "-t 15 -d dummy,lvm,shared,fs_lvm,fs_lvm_ssh,qcow2,ssh,ceph,vitastor,dev,vcenter,iscsi_libvirt"
]
DATASTORE_MAD = [
EXECUTABLE = "one_datastore",
- ARGUMENTS = "-t 15 -d dummy,fs,lvm,ceph,dev,iscsi_libvirt,vcenter,restic,rsync -s shared,ssh,ceph,fs_lvm,fs_lvm_ssh,qcow2,vcenter"
+ ARGUMENTS = "-t 15 -d dummy,fs,lvm,ceph,vitastor,dev,iscsi_libvirt,vcenter,restic,rsync -s shared,ssh,ceph,vitastor,fs_lvm,fs_lvm_ssh,qcow2,vcenter"
]
```
3. Добавьте строчки с INHERIT_DATASTORE_ATTR для двух атрибутов Vitastor-хранилищ:
```
INHERIT_DATASTORE_ATTR = "VITASTOR_CONF"
INHERIT_DATASTORE_ATTR = "IMAGE_PREFIX"
```
4. Добавьте TM_MAD_CONF и DS_MAD_CONF для Vitastor:
```
TM_MAD_CONF = [
NAME = "vitastor", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES",
DS_MIGRATE = "NO", DRIVER = "raw", ALLOW_ORPHANS="format",
TM_MAD_SYSTEM = "ssh,shared", LN_TARGET_SSH = "SYSTEM", CLONE_TARGET_SSH = "SYSTEM",
DISK_TYPE_SSH = "FILE", LN_TARGET_SHARED = "NONE",
CLONE_TARGET_SHARED = "SELF", DISK_TYPE_SHARED = "FILE"
]
DS_MAD_CONF = [
NAME = "vitastor",
REQUIRED_ATTRS = "DISK_TYPE,BRIDGE_LIST",
PERSISTENT_ONLY = "NO",
MARKETPLACE_ACTIONS = "export"
]
```
## Создайте хранилища
Примеры настроек хранилищ образов (image) и дисков ВМ (system):
[opennebula/vitastor-imageds.conf](../../opennebula/vitastor-imageds.conf) и
[opennebula/vitastor-systemds.conf](../../opennebula/vitastor-systemds.conf).
Скопируйте настройки и поменяйте следующие параметры так, как вам необходимо:
- POOL_NAME - имя пула Vitastor для сохранения образов дисков.
- IMAGE_PREFIX - строка, добавляемая в начало имён образов дисков.
- BRIDGE_LIST - список серверов с доступом к кластеру Vitastor, используемых для операций с хранилищем образов (image, не system).
- VITASTOR_CONF - путь к конфигурации Vitastor. Имейте в виду, что этот путь также надо добавить в `/etc/apparmor.d/local/abstractions/libvirt-qemu`, если вы используете AppArmor.
- STAGING_DIR - путь к временному каталогу, используемому при импорте внешних образов. Должен иметь достаточно свободного места, чтобы вмещать скачанные образы.
После этого создайте хранилища с помощью команд `onedatastore create vitastor-imageds.conf` и `onedatastore create vitastor-systemds.conf` (либо через UI).
## Блокировка доступа ВМ в Vitastor
Vitastor пока не поддерживает никакую аутентификацию, так что вы ДОЛЖНЫ заблокировать доступ гостевых ВМ
в кластер Vitastor на сетевом уровне.
Если вы используете VLAN-сети для ВМ - удостоверьтесь, что ВМ и гипервизор/сеть хранения помещены в разные
изолированные друг от друга VLAN-ы.
Если вы используете что-то более примитивное, например, мосты (bridge), вам, скорее всего, придётся вручную
настроить iptables / межсетевой экран, чтобы разрешить доступ к Vitastor только с IP гипервизоров.
Также в этом случае нужно будет переключить обычные мосты на "Bridged & Security Groups" и включить фильтр
спуфинга IP в OpenNebula. Правда, реализация этого фильтра пока не полная, и она не блокирует доступ к
локальным интерфейсам гипервизора. То есть, включённый фильтр спуфинга IP запрещает ВМ отправлять трафик
с чужими IP к другим ВМ или во внешний мир, но не запрещает отправлять его напрямую гипервизору. Чтобы
исправить это, тоже нужны дополнительные правила iptables.
Таким образом, более-менее полная блокировка при использовании простой сети на сетевых мостах может
выглядеть так (здесь `10.0.3.0/24` - подсеть ВМ, `10.0.2.0/24` - подсеть гипервизора):
```
# Разрешаем входящий трафик с физического устройства
iptables -A INPUT -m physdev --physdev-in eth0 -j ACCEPT
# Запрещаем трафик со всех ВМ, но с IP не из подсети ВМ
iptables -A INPUT ! -s 10.0.3.0/24 -i onebr0 -j DROP
# Запрещаем трафик от ВМ к сети гипервизора
iptables -I FORWARD 1 -s 10.0.3.0/24 -d 10.0.2.0/24 -j DROP
```
## Тестирование
Плагин OpenNebula по большей части состоит из bash-скриптов, и чтобы было понятнее, что они
вообще делают - ниже приведены описания процедур, которыми можно протестировать каждый из них.
| Скрипт | Описание | Как протестировать |
| ----------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------ |
| vmm/kvm/deploy.vitastor | Запустить виртуальную машину | Создайте и запустите виртуальную машину с дисками Vitastor: постоянным / непостоянным / волатильным (временным). |
| vmm/kvm/save.vitastor | Сохранить снимок памяти ВМ | Остановите виртуальную машину командой "Остановить". |
| vmm/kvm/restore.vitastor| Восстановить снимок памяти ВМ | Запустите ВМ после остановки обратно. |
| datastore/clone | Скопировать образ как "постоянный" | Создайте шаблон ВМ и создайте из него постоянную ВМ. |
| datastore/cp | Импортировать внешний образ | Импортируйте шаблон ВМ с образами дисков из Магазина OpenNebula. |
| datastore/export | Экспортировать образ как URL | Вероятно: экспортируйте шаблон ВМ с образами в Магазин. |
| datastore/mkfs | Создать образ с файловой системой | Хранилище → Образы → Создать → Тип: базовый блок данных, Расположение: пустой образ диска, Файловая система: любая непустая. |
| datastore/monitor | Вывод статистики места в хранилище образов | Проверьте статистику свободного/занятого места в списке хранилищ образов. |
| datastore/rm | Удалить "постоянный" образ | Хранилище → Образы → Выберите образ → Удалить. |
| datastore/snap_delete | Удалить снимок "постоянного" образа | Хранилище → Образы → Выберите образ → Выберите снимок → Удалить; <br> Чтобы создать образ со снимком: подключите постоянный образ к ВМ, создайте снимок, отключите образ. |
| datastore/snap_flatten | Откатить образ к снимку, удалив другие снимки | Хранилище → Образы → Выберите образ → Выберите снимок → "Выровнять" (flatten). |
| datastore/snap_revert | Откатить образ к снимку | Хранилище → Образы → Выберите образ → Выберите снимок → Откатить. |
| datastore/stat | Показать виртуальный размер образа в МБ | Неизвестно. По-видимому, в плагинах Vitastor и Ceph не используется. |
| tm/clone | Клонировать "непостоянный" образ в диск ВМ | Подключите "непостоянный" образ к ВМ. |
| tm/context | Создать диск контекстуализации ВМ | Создайте ВМ с контекстуализацией, как обычно. Но тестировать особенно нечего: в плагинах Vitastor и Ceph образ контекста хранится в локальной ФС гипервизора. |
| tm/cpds | Копировать диск ВМ/его снимок в новый образ | Выберите ВМ → Выберите диск → Опционально выберите снимок → "Сохранить как". |
| tm/delete | Удалить диск-клон или волатильный диск ВМ | Отключите волатильный или не-постоянный диск от ВМ. |
| tm/failmigrate | Обработать неудачную миграцию | Тестировать нечего. Скрипт пуст в плагинах Vitastor и Ceph. В других плагинах скрипт должен откатывать действия tm/premigrate. |
| tm/ln | Подключить "постоянный" образ к ВМ | Тестировать нечего. Скрипт пуст в плагинах Vitastor и Ceph. |
| tm/mkimage | Создать волатильный диск, без или с ФС | Подключите волатильный диск к ВМ, с или без файловой системы. |
| tm/mkswap | Создать волатильный диск подкачки | Подключите волатильный диск к ВМ, форматированный как диск подкачки (swap). |
| tm/monitor | Вывод статистики места в хранилище дисков ВМ | Проверьте статистику свободного/занятого места в списке хранилищ дисков ВМ. |
| tm/mv | Мигрировать диск ВМ между хостами | Мигрируйте ВМ между серверами. Правда, с точки зрения хранилища в плагинах Vitastor и Ceph этот скрипт ничего не делает. |
| tm/mvds | Отключить "постоянный" образ от ВМ | Тестировать нечего. Скрипт пуст в плагинах Vitastor и Ceph. В целом же скрипт обратный к tm/ln и в других хранилищах он может, например, копировать образ ВМ с диска гипервизора обратно в хранилище. |
| tm/postbackup | Выполняется после бэкапа | По-видимому, скрипт просто удаляет временные файлы после резервного копирования. Так что можно провести его и проверить, что на серверах не осталось временных файлов. |
| tm/postbackup_live | Выполняется после бэкапа запущенной ВМ | То же, что tm/postbackup, но для запущенной ВМ. |
| tm/postmigrate | Выполняется после миграции ВМ | Тестировать нечего. Однако, OpenNebula запускает скрипт только для системного хранилища, поэтому он вызывает аналогичные скрипты для хранилищ других дисков той же ВМ. Помимо этого в плагинах Vitastor и Ceph скрипт ничего не делает. |
| tm/prebackup | Выполнить резервное копирование дисков ВМ | Создайте хранилище резервных копий типа "rsync" → Забэкапьте в него ВМ. |
| tm/prebackup_live | То же самое для запущенной ВМ | То же, что tm/prebackup, но запускает fsfreeze/thaw (остановку доступа к дискам). Так что смысл теста - проведите резервное копирование и проверьте, что данные скопировались консистентно. |
| tm/premigrate | Выполняется перед миграцией ВМ | Тестировать нечего. Аналогично tm/postmigrate запускается только для системного хранилища. |
| tm/resize | Изменить размер диска ВМ | Выберите ВМ → Выберите непостоянный диск → Измените его размер. |
| tm/restore | Восстановить диски ВМ из бэкапа | Создайте хранилище резервных копий → Забэкапьте в него ВМ → Восстановите её обратно. |
| tm/snap_create | Создать снимок диска ВМ | Выберите ВМ → Выберите диск → Создайте снимок. |
| tm/snap_create_live | Создать снимок диска запущенной ВМ | Выберите запущенную ВМ → Выберите диск → Создайте снимок. |
| tm/snap_delete | Удалить снимок диска ВМ | Выберите ВМ → Выберите диск → Выберите снимок → Удалить. |
| tm/snap_revert | Откатить диск ВМ к снимку | Выберите ВМ → Выберите диск → Выберите снимок → Откатить. |

View File

@ -6,150 +6,19 @@
# Architecture # Architecture
- [Server-side components](#server-side-components)
- [Basic concepts](#basic-concepts) - [Basic concepts](#basic-concepts)
- [Client-side components](#client-side-components)
- [Additional utilities](#additional-utilities)
- [Overall read/write process](#overall-read-write-process)
- [Nuances of request handling](#nuances-of-request-handling)
- [Similarities to Ceph](#similarities-to-ceph) - [Similarities to Ceph](#similarities-to-ceph)
- [Differences from Ceph](#differences-from-ceph) - [Differences from Ceph](#differences-from-ceph)
- [Implementation Principles](#implementation-principles) - [Implementation Principles](#implementation-principles)
## Server-side components
- **OSD** (Object Storage Daemon) is a process that directly works with the disk, stores data
and serves read/write requests. One OSD serves one disk (or one partition). OSDs talk to etcd
and to each other — they receive cluster state from etcd, and send read/write requests for
secondary copies of data to other OSDs.
- **etcd** — clustered key/value database, used as a reliable storage for configuration
and high-level cluster state. Etcd is the component that prevents splitbrain in the cluster.
Data blocks are not stored in etcd, etcd doesn't participate in data write or read path.
- **Монитор** — a separate node.js based daemon which monitors the cluster, calculates
required configuration changes and saves them to etcd, thus commanding OSDs to apply these
changes. Monitor also aggregates cluster statistics. OSD don't talk to monitor, monitor
only sends and receives data from etcd.
## Basic concepts ## Basic concepts
- **Pool** is a container for data that has equal redundancy scheme and disk placement rules. - OSD (Object Storage Daemon) is a process that stores data and serves read/write requests.
- **PG (Placement Group)** is a "shard" of the cluster, subdivision unit that has its own - PG (Placement Group) is a "shard" of the cluster, group of data stored on one set of replicas.
set of OSDs for data storage. - Pool is a container for data that has equal redundancy scheme and placement rules.
- **Failure Domain** is a group of OSDs, from the simultaneous failure of which you are - Monitor is a separate daemon that watches cluster state and handles failures.
protected by Vitastor. Default failure domain is "host" (server), but you choose a - Failure Domain is a group of OSDs that you allow to fail. It's "host" by default.
larger (for example, a rack of servers) or smaller (a single drive) failure domain - Placement Tree groups OSDs in a hierarchy to later split them into Failure Domains.
for every pool.
- **Placement Tree** (similar to Ceph CRUSH Tree) groups OSDs in a hierarchy to later
split them into Failure Domains.
## Client-side components
- **Client library** encapsulates client I/O logic. Client library connects to etcd and to all OSDs,
receives cluster state from etcd, sends read and write requests directly to all OSDs. Due
to the symmetric distributed architecture, all data blocks (each 128 KB by default) are placed
to different OSDs, but clients always know where each data block is stored and connect directly
to the right OSD.
All other client-side components are based on the client library:
- **[vitastor-cli](../usage/cli.en.md)** — command-line utility for cluster management.
Allows to view cluster state, manage pools and images, i.e. create, modify and remove
virtual disks, their snapshots and clones.
- **[QEMU driver](../usage/qemu.en.md)** — pluggable QEMU module allowing QEMU/KVM virtual
machines work with virtual Vitastor disks directly from userspace through the client library,
without the need to attach disks as kernel block devices. However, if you want to attach
disks, you can also do that with the same driver and [VDUSE](../usage/qemu.en.md#vduse).
- **[vitastor-nbd](../usage/nbd.en.md)** — utility that allows to attach Vitastor disks as
kernel block devices using NBD (Network Block Device), which works more like "BUSE"
(Block Device In Userspace). Vitastor doesn't have Linux kernel modules for the same task
(at least by now). NBD is an older, non-recommended way to attach disks — you should use
VDUSE whenever you can.
- **[CSI driver](../installation/kubernetes.en.md)** — driver for attaching Vitastor images
as Kubernetes persistent volumes. Works through VDUSE (when available) or NBD — images are
attached as kernel block devices and mounted into containers.
- **Drivers for Proxmox, OpenStack and so on** — pluggable modules for corresponding systems,
allowing to use Vitastor as storage in them.
- **[vitastor-nfs](../usage/nfs.en.md)** — NFS 3.0 server allowing export of two file system variants:
the first is a simplified pseudo-FS for file-based access to Vitastor block images (for non-QEMU
hypervisors with NFS support), the second is **VitastorFS**, full-featured clustered POSIX FS.
Both variants support parallel access from multiple vitastor-nfs servers. In fact, you are
not required to setup separate NFS servers at all and use vitastor-nfs mount command on every
client node — it starts the NFS server and mounts the FS locally.
- **[fio driver](../usage/fio.en.md)** — pluggable module for fio disk benchmarking tool for
running performance tests on your Vitastor cluster.
- **vitastor-kv** — client for a key-value DB working over shared block volumes (usual
vitastor images). VitastorFS metadata is stored in vitastor-kv.
## Additional utilities
- **vitastor-disk** — a Vitastor OSD disk management tool. You can create, remove,
resize and move OSD partitions with it.
## Overall read/write process
- Vitastor stores virtual disks, also named "images" or "inodes".
- Each image is stored in some pool. Pool specifies storage parameters such as redundancy
scheme (replication or EC — erasure codes, i.e. error correction codes), failure domain
and restrictions on OSD selection for image data placement. See [Pool configuration](../config/pool.en.md) for details.
- Each image is split into objects/blocks of fixed size, equal to [block_size](../config/layout-cluster.en.md#block_size)
(128 KB by default), multiplied by data part count for EC or 1 for replicas. That is,
if a pool uses EC 4+2 coding scheme (4 data parts + 2 parity parts), then, with the
default block_size, images are split into 512 KB objects.
- Client read/write requests are split into parts at object boundaries.
- Each object is mapped to a PG number it belongs to, by simply taking a remainder of
division of its offset by PG count of the image's pool.
- Client reads primary OSD for all PGs from etcd. Primary OSD for each PG is assigned
by the monitor during cluster operation, along with the full PG OSD set.
- If not already connected, client connects to primary OSDs of all PGs involved in a
read/write request and sends parts of the request to them.
- If a primary OSD is unavailable, client retries connection attempts indefinitely
either until it becomes available or until the monitor assigns another OSD as primary
for that PG.
- Client also retries requests if the primary OSD replies with error code EPIPE, meaning
that the PG is inactive at this OSD at the moment - for example, when the primary OSD
is switched, or if the primary OSD itself loses connection to replicas during request
handling.
- Primary OSD determines where the parts of the object are stored. By default, all objects
are assumed to be stored at the target OSD set of a PG, but some of them may be present
at a different OSD set if they are degraded or moved, or if the data rebalancing process
is active. OSDs doesn't do any network requests, if calculates locations of all objects
during PG activation and stores it in memory.
- Primary OSD handles the request locally when it can - for example, when it's a read
from a replicated pool or when it's a read from a EC pool involving only one data part
stored on the OSD's local disk.
- When a request requires reads or writes to additional OSDs, primary OSD uses already
established connections to secondary OSDs of the PG to execute these requests. This happens
in parallel to local disk operations. All such connections are guaranteed to be already
established when the PG is active, and if any of them is dropped, PG is restarted and
all current read/write operations to it fail with EPIPE error and are retried by clients.
- After completing all secondary read/write requests, primary OSD sends the response to
the client.
### Nuances of request handling
- If a pool uses erasure codes and some of the OSDs are unavailable, primary OSDs recover
data from the remaining parts during read.
- Each object has a version number. During write, primary OSD first determines the current
version of the object. As primary OSD usually stores the object or its part itself, most
of the time version is read from the memory of the OSD itself. However, if primary OSD
doesn't contain parts of the object, it requests the version number from a secondary OSD
which has that part. Such request still doesn't involve reading from the disk though,
because object metadata, including version number, is always stored in OSD memory.
- If a pool uses erasure codes, partial writes of an object require reading other parts of
it from secondary OSDs or from the local disk of the primary OSD itself. This is called
"read-modify-write" process.
- If a pool uses erasure codes, two-phase write process is used to get rid of the Write Hole
problem: first a new version of object parts is written to all secondary OSDs without
removing the previous version, and then, after receiving successful write confirmations
from all OSDs, new version is committed and the old one is allowed to be removed.
- In a pool doesn't use immediate_commit mode, then write requests sent by clients aren't
treated as committed to physical media instantly. Clients have to send separate type of
requests (SYNC) to commit changes, and before it isn't sent, new versions of data are
allowed to be lost if some OSDs die. Thus, when immediate_commit is disabled, clients
store copies of all write requests in memory and repeat them from there when the
connection to primary OSD is lost. This in-memory copy is removed after a successful
SYNC, and to prevent excessive memory usage, clients also do an automatic SYNC
every [client_dirty_limit](../config/network.en.md#client_dirty_limit) written bytes.
## Similarities to Ceph ## Similarities to Ceph
@ -218,5 +87,5 @@ All other client-side components are based on the client library:
- Deleting images in a degraded cluster may currently lead to objects reappearing - Deleting images in a degraded cluster may currently lead to objects reappearing
after dead OSDs come back, and in case of erasure-coded pools, they may even after dead OSDs come back, and in case of erasure-coded pools, they may even
reappear as incomplete. Just repeat the removal request again in this case. reappear as incomplete. Just repeat the removal request again in this case.
This problem will be fixed in the future, along with the metadata disk storage This problem will be fixed in the nearest future, the fix is already implemented
format update. in the "epoch-deletions" branch.

View File

@ -11,7 +11,6 @@
- [Серверные компоненты](#серверные-компоненты) - [Серверные компоненты](#серверные-компоненты)
- [Базовые понятия](#базовые-понятия) - [Базовые понятия](#базовые-понятия)
- [Клиентские компоненты](#клиентские-компоненты) - [Клиентские компоненты](#клиентские-компоненты)
- [Дополнительные утилиты](#дополнительные-утилиты)
- [Общий процесс записи и чтения](#общий-процесс-записи-и-чтения) - [Общий процесс записи и чтения](#общий-процесс-записи-и-чтения)
- [Особенности обработки запросов](#особенности-обработки-запросов) - [Особенности обработки запросов](#особенности-обработки-запросов)
- [Схожесть с Ceph](#схожесть-с-ceph) - [Схожесть с Ceph](#схожесть-с-ceph)
@ -24,8 +23,8 @@
Один OSD управляет одним диском (или разделом). OSD общаются с etcd и друг с другом — от etcd они Один OSD управляет одним диском (или разделом). OSD общаются с etcd и друг с другом — от etcd они
получают состояние кластера, а друг другу передают запросы записи и чтения вторичных копий данных. получают состояние кластера, а друг другу передают запросы записи и чтения вторичных копий данных.
- **etcd** — кластерная key/value база данных, используется для хранения настроек и верхнеуровневого - **etcd** — кластерная key/value база данных, используется для хранения настроек и верхнеуровневого
состояния кластера, а также предотвращения разделения сознания (splitbrain). Блоки данных в etcd не состояния кластера, а также предотвращения разделения сознания. Блоки данных в etcd не хранятся,
хранятся, в обработке клиентских запросов чтения и записи etcd не участвует. в обработке клиентских запросов чтения и записи etcd не участвует.
- **Монитор** — отдельный демон на node.js, рассчитывающий необходимые изменения в конфигурацию - **Монитор** — отдельный демон на node.js, рассчитывающий необходимые изменения в конфигурацию
кластера, сохраняющий эту информацию в etcd и таким образом командующий OSD применить эти изменения. кластера, сохраняющий эту информацию в etcd и таким образом командующий OSD применить эти изменения.
Также агрегирует статистику. Контактирует только с etcd, OSD с монитором не общаются. Также агрегирует статистику. Контактирует только с etcd, OSD с монитором не общаются.
@ -35,55 +34,40 @@
- **Пул (Pool)** — контейнер для данных, имеющих одну и ту же схему избыточности и правила распределения по OSD. - **Пул (Pool)** — контейнер для данных, имеющих одну и ту же схему избыточности и правила распределения по OSD.
- **PG (Placement Group)** — "шард", единица деления пулов в кластере, которой назначается свой набор - **PG (Placement Group)** — "шард", единица деления пулов в кластере, которой назначается свой набор
OSD для хранения данных (копий или частей объектов). OSD для хранения данных (копий или частей объектов).
- **Домен отказа (Failure Domain)** — группа OSD, от одновременного падения которых должен защищать - **Домен отказа (Failure Domain)** — группа OSD, одновременное падение которых рассматривается
Vitastor. По умолчанию домен отказа — "host" (сервер), но вы можете установить для пула как больший как вероятное. По умолчанию это "host" (сервер).
домен отказа (например, стойку серверов), так и меньший (например, отдельный диск).
- **Дерево распределения** (Placement Tree, в Ceph CRUSH Tree) — иерархическая группировка OSD - **Дерево распределения** (Placement Tree, в Ceph CRUSH Tree) — иерархическая группировка OSD
в узлы, которые далее можно использовать как домены отказа. в узлы, которые далее можно использовать как домены отказа.
## Клиентские компоненты ## Клиентские компоненты
- **Клиентская библиотека** — инкапсулирует логику на стороне клиента. Соединяется с etcd и со всеми OSD, - **Клиентская библиотека** — инкапсулирует логику на стороне клиента. Соединяются с etcd и со всеми OSD,
от etcd получает состояние кластера, команды чтения и записи отправляет на все OSD напрямую. от etcd получают состояние кластера, команды чтения и записи отправляют на все OSD напрямую.
В силу архитектуры все отдельные блоки данных (по умолчанию по 128 КБ) располагается на разных В силу архитектуры все отдельные блоки данных (по умолчанию по 128 КБ) располагается на разных
OSD, но клиент устроен так, что всегда точно знает, к какому OSD обращаться, и подключается OSD, но клиент устроен так, что всегда точно знает, к какому OSD обращаться, и подключается
к нему напрямую. к нему напрямую.
На базе клиентской библиотеки реализованы все остальные клиенты: На базе клиентской библиотеки реализованы все остальные клиенты:
- **[vitastor-cli](../usage/cli.ru.md)** — утилита командной строки для управления кластером. - **vitastor-cli** — утилита командной строки для управления кластером. В данный момент позволяет
Позволяет просматривать общее состояние кластера, управлять пулами и образами — то есть просматривать общее состояние кластера и управлять образами — т.е. создавать, менять и удалять
создавать, менять и удалять виртуальные диски, их снимки и клоны. виртуальные диски, их снимки и клоны.
- **[Драйвер QEMU](../usage/qemu.ru.md)** — подключаемый модуль QEMU, позволяющий QEMU/KVM - **Драйвер QEMU** — подключаемый модуль QEMU, позволяющий QEMU/KVM виртуальным машинам работать
виртуальным машинам работать с виртуальными дисками Vitastor напрямую из пространства пользователя с виртуальными дисками Vitastor напрямую из пространства пользователя с помощью клиентской
с помощью клиентской библиотеки, без необходимости подключения дисков в виде блочных устройств библиотеки, без необходимости отображения дисков в виде блочных устройств. Тот же драйвер
Linux. Если, однако, вы хотите подключать диски в виде блочных устройств, то вы тоже можете позволяет подключать диски в систему через [VDUSE](../usage/qemu.ru.md#vduse).
сделать это с помощью того же самого драйвера и [VDUSE](../usage/qemu.ru.md#vduse). - **vitastor-nbd** — утилита, позволяющая монтировать образы Vitastor в виде блочных устройств
- **[vitastor-nbd](../usage/nbd.ru.md)** — утилита, позволяющая монтировать образы Vitastor с помощью NBD (Network Block Device), на самом деле скорее работающего как "BUSE"
в виде блочных устройств с помощью NBD (Network Block Device), на самом деле скорее работающего (Block Device In Userspace). Модуля ядра Linux для выполнения той же задачи в Vitastor нет
как "BUSE" (Block Device In Userspace). Модуля ядра Linux для выполнения той же задачи в (по крайней мере, пока).
Vitastor нет (по крайней мере, пока). NBD — более старый и нерекомендуемый способ подключения - **CSI драйвер** — драйвер для подключения Vitastor-образов в виде персистентных томов (PV) Kubernetes.
дисков — вам следует использовать VDUSE всегда, когда это возможно. Работает через vitastor-nbd — образы отражаются в виде блочных устройств и монтируются
- **[CSI драйвер](../installation/kubernetes.ru.md)** — драйвер для подключения Vitastor-образов в контейнеры.
в виде персистентных томов (PV) Kubernetes. Работает через VDUSE (если доступно) или через
NBD — образы отражаются в виде блочных устройств и монтируются в контейнеры.
- **Драйвера Proxmox, OpenStack и т.п.** — подключаемые модули для соответствующих систем, - **Драйвера Proxmox, OpenStack и т.п.** — подключаемые модули для соответствующих систем,
позволяющие использовать Vitastor как хранилище в оных. позволяющие использовать Vitastor как хранилище в оных.
- **[vitastor-nfs](../usage/nfs.ru.md)** — NFS 3.0 сервер, предоставляющий два варианта файловой системы: - **vitastor-nfs** — утилита, предоставляющая файловый доступ к образам в кластере Vitastor
первая — упрощённая для файлового доступа к блочным образам (для не-QEMU гипервизоров, поддерживающих NFS), по протоколу NFS 3.0. Предназначена для гипервизоров, не основанных на QEMU и Linux, но при
вторая — VitastorFS, полноценная кластерная POSIX ФС. Оба варианта поддерживают параллельный этом поддерживающих NFS.
доступ с нескольких vitastor-nfs серверов. На самом деле можно вообще не выделять
отдельные NFS-серверы, а вместо этого использовать команду vitastor-nfs mount, запускающую
NFS-сервер прямо на клиентской машине и монтирующую ФС локально.
- **[Драйвер fio](../usage/fio.ru.md)** — подключаемый модуль для утилиты тестирования
производительности дисков fio, позволяющий тестировать Vitastor-кластеры.
- **vitastor-kv** — клиент для key-value базы данных, работающей поверх разделяемого блочного
образа (обычного блочного образа vitastor). Метаданные VitastorFS хранятся именно в vitastor-kv.
## Дополнительные утилиты
- **vitastor-disk** — утилита для разметки дисков под Vitastor OSD. С её помощью можно
создавать, удалять, менять размеры или перемещать разделы OSD.
## Общий процесс записи и чтения ## Общий процесс записи и чтения
@ -114,22 +98,16 @@
находиться на других OSD, если эти объекты деградированы или перемещены, или идёт процесс находиться на других OSD, если эти объекты деградированы или перемещены, или идёт процесс
ребаланса. Запросы для проверки по сети не отправляются, информация о местоположении всех ребаланса. Запросы для проверки по сети не отправляются, информация о местоположении всех
объектов рассчитывается первичным OSD при активации PG и хранится в памяти. объектов рассчитывается первичным OSD при активации PG и хранится в памяти.
- Когда это возможно, первичный OSD обрабатывает запрос локально. Например, так происходит - Первичный OSD соединяется (если ещё не соединён) с вторичными OSD, на которых располагаются
при чтениях объектов из пулов с репликацией или при чтении из EC пула, затрагивающего части объекта, и отправляет им запросы чтения/записи, а также читает/пишет из/в своё локальное
только часть, хранимую на диске самого первичного OSD. хранилище, если сам входит в набор.
- Когда запрос требует записи или чтения с вторичных OSD, первичный OSD использует заранее
установленные соединения с ними для выполнения этих запросов. Это происходит параллельно
локальным операциям чтения/записи с диска самого OSD. Так как соединения к вторичным OSD PG
устанавливаются при её запуске, то они уже гарантированно установлены, когда PG активна,
и если любое из этих соединений отключается, PG перезапускается, а все текущие запросы чтения
и записи в неё завершаются с ошибкой EPIPE, после чего повторяются клиентами.
- После завершения всех вторичных операций чтения/записи первичный OSD отправляет ответ клиенту. - После завершения всех вторичных операций чтения/записи первичный OSD отправляет ответ клиенту.
### Особенности обработки запросов ### Особенности обработки запросов
- Если в пуле используются коды коррекции ошибок и при этом часть OSD недоступна, первичный - Если в пуле используются коды коррекции ошибок и при этом часть OSD недоступна, первичный
OSD при чтении восстанавливает данные из оставшихся частей. OSD при чтении восстанавливает данные из оставшихся частей.
- Каждый объект имеет номер версии. При записи объекта первичный OSD сначала получает номер - Каждый объект имеет номер версии. При записи объекта первичный OSD сначала читает из номер
версии объекта. Так как первичный OSD обычно сам хранит копию или часть объекта, номер версии объекта. Так как первичный OSD обычно сам хранит копию или часть объекта, номер
версии обычно читается из памяти самого OSD. Однако, если ни одна часть обновляемого объекта версии обычно читается из памяти самого OSD. Однако, если ни одна часть обновляемого объекта
не находится на первичном OSD, для получения номера версии он обращается к одному из вторичных не находится на первичном OSD, для получения номера версии он обращается к одному из вторичных
@ -137,20 +115,20 @@
так как метаданные объектов, включая номер версии, все OSD хранят в памяти. так как метаданные объектов, включая номер версии, все OSD хранят в памяти.
- Если в пуле используются коды коррекции ошибок, перед частичной записью объекта для вычисления - Если в пуле используются коды коррекции ошибок, перед частичной записью объекта для вычисления
чётности зачастую требуется чтение частей объекта с вторичных OSD или с локального диска чётности зачастую требуется чтение частей объекта с вторичных OSD или с локального диска
самого первичного OSD. Это называется процессом "чтение-модификация-запись" (read-modify-write). самого первичного OSD.
- Если в пуле используются коды коррекции ошибок, для закрытия Write Hole применяется - Также, если в пуле используются коды коррекции ошибок, для закрытия Write Hole применяется
двухфазный алгоритм записи: сначала на все вторичные OSD записывается новая версия частей двухфазный алгоритм записи: сначала на все вторичные OSD записывается новая версия частей
объекта, но при этом старая версия не удаляется, а потом, после получения подтверждения объекта, но при этом старая версия не удаляется, а потом, после получения подтверждения
успешной записи от всех вторичных OSD, новая версия фиксируется и разрешается удаление старой. успешной записи от всех вторичных OSD, новая версия фиксируется и разрешается удаление старой.
- Если в пуле не включён режим immediate_commit, то запросы записи, отправляемые клиентами, - Если в кластере не включён режим immediate_commit, то запросы записи, отправляемые клиентами,
не считаются зафиксированными на физических накопителях сразу. Для фиксации данных клиенты не считаются зафиксированными на физических накопителях сразу. Для фиксации данных клиенты
должны отдельно отправлять запросы SYNC (отдельный от чтения и записи вид запроса), должны отдельно отправлять запросы SYNC (отдельный от чтения и записи вид запроса),
а пока такой запрос не отправлен, считается, что записанные данные могут исчезнуть, а пока такой запрос не отправлен, считается, что записанные данные могут исчезнуть,
если соответствующий OSD упадёт. Поэтому, когда режим immediate_commit отключён, все если соответствующий OSD упадёт. Поэтому, когда режим immediate_commit отключён, все
запросы записи клиенты копируют в памяти и при потере соединения и повторном соединении запросы записи клиенты копируют в памяти и при потере соединения и повторном соединении
с OSD повторяют из памяти. Скопированные в память данные удаляются при успешном SYNC, с OSD повторяют из памяти. Скопированные в память данные удаляются при успешном fsync,
а чтобы хранение этих данных не приводило к чрезмерному потреблению памяти, клиенты а чтобы хранение этих данных не приводило к чрезмерному потреблению памяти, клиенты
автоматически выполняют SYNC каждые [client_dirty_limit](../config/network.ru.md#client_dirty_limit) автоматически выполняют fsync каждые [client_dirty_limit](../config/network.ru.md#client_dirty_limit)
записанных байт. записанных байт.
## Схожесть с Ceph ## Схожесть с Ceph
@ -227,5 +205,5 @@
- Удаление образов в деградированном кластере может в данный момент приводить к повторному - Удаление образов в деградированном кластере может в данный момент приводить к повторному
"появлению" удалённых объектов после поднятия отключённых OSD, причём в случае EC-пулов, "появлению" удалённых объектов после поднятия отключённых OSD, причём в случае EC-пулов,
объекты могут появиться в виде "неполных". Если вы столкнётесь с такой ситуацией, просто объекты могут появиться в виде "неполных". Если вы столкнётесь с такой ситуацией, просто
повторите запрос удаления. Данная проблема будет исправлена в будущем вместе с обновлением повторите запрос удаления. Исправление этой проблемы уже реализовано в ветке "epoch-deletions"
дискового формата хранения метаданных. и вскоре будет включено в релиз.

View File

@ -39,10 +39,6 @@
## Plugins and tools ## Plugins and tools
- [Proxmox storage plugin and packages](../installation/proxmox.en.md)
- [OpenNebula storage plugin](../installation/opennebula.en.md)
- [CSI plugin for Kubernetes](../installation/kubernetes.en.md)
- [OpenStack support: Cinder driver, Nova and libvirt patches](../installation/openstack.en.md)
- [Debian and CentOS packages](../installation/packages.en.md) - [Debian and CentOS packages](../installation/packages.en.md)
- [Image management CLI (vitastor-cli)](../usage/cli.en.md) - [Image management CLI (vitastor-cli)](../usage/cli.en.md)
- [Disk management CLI (vitastor-disk)](../usage/disk.en.md) - [Disk management CLI (vitastor-disk)](../usage/disk.en.md)
@ -50,6 +46,9 @@
- [Native QEMU driver](../usage/qemu.en.md) - [Native QEMU driver](../usage/qemu.en.md)
- [Loadable fio engine for benchmarks](../usage/fio.en.md) - [Loadable fio engine for benchmarks](../usage/fio.en.md)
- [NBD proxy for kernel mounts](../usage/nbd.en.md) - [NBD proxy for kernel mounts](../usage/nbd.en.md)
- [CSI plugin for Kubernetes](../installation/kubernetes.en.md)
- [OpenStack support: Cinder driver, Nova and libvirt patches](../installation/openstack.en.md)
- [Proxmox storage plugin and packages](../installation/proxmox.en.md)
- [Simplified NFS proxy for file-based image access emulation (suitable for VMWare)](../usage/nfs.en.md#pseudo-fs) - [Simplified NFS proxy for file-based image access emulation (suitable for VMWare)](../usage/nfs.en.md#pseudo-fs)
## Roadmap ## Roadmap
@ -59,6 +58,7 @@ The following features are planned for the future:
- Control plane optimisation - Control plane optimisation
- Other administrative tools - Other administrative tools
- Web GUI - Web GUI
- OpenNebula plugin
- iSCSI and NVMeoF gateways - iSCSI and NVMeoF gateways
- Multi-threaded client - Multi-threaded client
- Faster failover - Faster failover

View File

@ -41,10 +41,6 @@
## Драйверы и инструменты ## Драйверы и инструменты
- [Плагин для Proxmox](../installation/proxmox.ru.md)
- [Плагин для OpenNebula](../installation/opennebula.ru.md)
- [CSI-плагин для Kubernetes](../installation/kubernetes.ru.md)
- [Базовая поддержка OpenStack: драйвер Cinder, патчи для Nova и libvirt](../installation/openstack.ru.md)
- [Пакеты для Debian и CentOS](../installation/packages.ru.md) - [Пакеты для Debian и CentOS](../installation/packages.ru.md)
- [Консольный интерфейс управления образами (vitastor-cli)](../usage/cli.ru.md) - [Консольный интерфейс управления образами (vitastor-cli)](../usage/cli.ru.md)
- [Инструмент управления дисками (vitastor-disk)](../usage/disk.ru.md) - [Инструмент управления дисками (vitastor-disk)](../usage/disk.ru.md)
@ -52,6 +48,9 @@
- [Драйвер диска для QEMU](../usage/qemu.ru.md) - [Драйвер диска для QEMU](../usage/qemu.ru.md)
- [Драйвер диска для утилиты тестирования производительности fio](../usage/fio.ru.md) - [Драйвер диска для утилиты тестирования производительности fio](../usage/fio.ru.md)
- [NBD-прокси для монтирования образов ядром](../usage/nbd.ru.md) ("блочное устройство в режиме пользователя") - [NBD-прокси для монтирования образов ядром](../usage/nbd.ru.md) ("блочное устройство в режиме пользователя")
- [CSI-плагин для Kubernetes](../installation/kubernetes.ru.md)
- [Базовая поддержка OpenStack: драйвер Cinder, патчи для Nova и libvirt](../installation/openstack.ru.md)
- [Плагин для Proxmox](../installation/proxmox.ru.md)
- [Упрощённая NFS-прокси для эмуляции файлового доступа к образам (подходит для VMWare)](../usage/nfs.ru.md#псевдо-фс) - [Упрощённая NFS-прокси для эмуляции файлового доступа к образам (подходит для VMWare)](../usage/nfs.ru.md#псевдо-фс)
## Планы развития ## Планы развития
@ -59,6 +58,7 @@
- Оптимизация слоя управления - Оптимизация слоя управления
- Другие инструменты администрирования - Другие инструменты администрирования
- Web-интерфейс - Web-интерфейс
- Плагин для OpenNebula
- iSCSI и NVMeoF прокси - iSCSI и NVMeoF прокси
- Многопоточный клиент - Многопоточный клиент
- Более быстрое переключение при отказах - Более быстрое переключение при отказах

View File

@ -32,7 +32,7 @@
- SATA SSD: Micron 5100/5200/5300/5400, Samsung PM863/PM883/PM893, Intel D3-S4510/4520/4610/4620, Kingston DC500M - SATA SSD: Micron 5100/5200/5300/5400, Samsung PM863/PM883/PM893, Intel D3-S4510/4520/4610/4620, Kingston DC500M
- NVMe: Micron 9100/9200/9300/9400, Micron 7300/7450, Samsung PM983/PM9A3, Samsung PM1723/1735/1743, - NVMe: Micron 9100/9200/9300/9400, Micron 7300/7450, Samsung PM983/PM9A3, Samsung PM1723/1735/1743,
Intel DC-P3700/P4500/P4600, Intel D5-P4320, Intel D7-P5500/P5600, Intel Optane, Kingston DC1000B/DC1500M Intel DC-P3700/P4500/P4600, Intel D7-P5500/P5600, Intel Optane, Kingston DC1000B/DC1500M
- HDD: HGST Ultrastar, Toshiba MG, Seagate EXOS - HDD: HGST Ultrastar, Toshiba MG, Seagate EXOS
## Configure monitors ## Configure monitors

View File

@ -22,7 +22,7 @@
использовать и десктопные SSD, включив режим отложенного fsync, но производительность будет хуже. использовать и десктопные SSD, включив режим отложенного fsync, но производительность будет хуже.
О конденсаторах читайте [здесь](../config/layout-cluster.ru.md#immediate_commit). О конденсаторах читайте [здесь](../config/layout-cluster.ru.md#immediate_commit).
- Если хотите использовать HDD, берите современные модели с Media или SSD кэшем - HGST Ultrastar, - Если хотите использовать HDD, берите современные модели с Media или SSD кэшем - HGST Ultrastar,
Toshiba MG, Seagate EXOS или что-то похожее. Если такого кэша у ваших дисков нет, Toshiba MG08, Seagate EXOS или что-то похожее. Если такого кэша у ваших дисков нет,
обязательно возьмите SSD под метаданные и журнал (маленькие, буквально 2 ГБ на 1 ТБ HDD-места). обязательно возьмите SSD под метаданные и журнал (маленькие, буквально 2 ГБ на 1 ТБ HDD-места).
- Возьмите быструю сеть, минимум 10 гбит/с. Идеал - что-то вроде Mellanox ConnectX-4 с RoCEv2. - Возьмите быструю сеть, минимум 10 гбит/с. Идеал - что-то вроде Mellanox ConnectX-4 с RoCEv2.
- Для лучшей производительности отключите энергосбережение CPU: `cpupower idle-set -D 0 && cpupower frequency-set -g performance`. - Для лучшей производительности отключите энергосбережение CPU: `cpupower idle-set -D 0 && cpupower frequency-set -g performance`.
@ -32,8 +32,8 @@
- SATA SSD: Micron 5100/5200/5300/5400, Samsung PM863/PM883/PM893, Intel D3-S4510/4520/4610/4620, Kingston DC500M - SATA SSD: Micron 5100/5200/5300/5400, Samsung PM863/PM883/PM893, Intel D3-S4510/4520/4610/4620, Kingston DC500M
- NVMe: Micron 9100/9200/9300/9400, Micron 7300/7450, Samsung PM983/PM9A3, Samsung PM1723/1735/1743, - NVMe: Micron 9100/9200/9300/9400, Micron 7300/7450, Samsung PM983/PM9A3, Samsung PM1723/1735/1743,
Intel DC-P3700/P4500/P4600, Intel D5-P4320, Intel D7-P5500/P5600, Intel Optane, Kingston DC1000B/DC1500M Intel DC-P3700/P4500/P4600, Intel D7-P5500/P5600, Intel Optane, Kingston DC1000B/DC1500M
- HDD: HGST Ultrastar, Toshiba MG, Seagate EXOS - HDD: HGST Ultrastar, Toshiba MG06/MG07/MG08, Seagate EXOS
## Настройте мониторы ## Настройте мониторы

View File

@ -169,25 +169,6 @@ Upgrading is performed without stopping clients (VMs/containers), you just need
upgrade and restart servers one by one. However, ideally you should restart VMs too upgrade and restart servers one by one. However, ideally you should restart VMs too
to make them use the new version of the client library. to make them use the new version of the client library.
### 1.7.x to 1.8.0
It's recommended to upgrade from version <= 1.7.x to version >= 1.8.0 with full downtime,
i.e. you should first stop clients and then the cluster (OSDs and monitor), because 1.8.0
includes a fix for etcd event stream inconsistency which could lead to "incomplete" objects
appearing in EC pools, and in rare cases, probably, even to data corruption during mass OSD
restarts. It doesn't mean that you WILL hit this problem if you upgrade without full downtime,
but it's better to secure yourself against it.
Also, if you upgrade version from <= 1.7.x to version >= 1.8.0, BUT <= 1.9.0: restart all clients
(VMs and so on), otherwise they will hang when monitor clears old PG configuration key,
which happens 24 hours after upgrade.
This is fixed in 1.9.1. So, after upgrading version <= 1.7.x directly to version >= 1.9.1,
you DO NOT have to restart all old clients immediately - they will work like before until
you decide to upgrade them too. The downside is that you'll have to remove the old PG
configuration key (`/vitastor/config/pgs`) from etcd by hand when you make sure that all
your clients are restarted.
### 1.1.x to 1.2.0 ### 1.1.x to 1.2.0
Upgrading version <= 1.1.x to version >= 1.2.0, if you use EC n+k with k>=2, is recommended Upgrading version <= 1.1.x to version >= 1.2.0, if you use EC n+k with k>=2, is recommended

View File

@ -166,25 +166,6 @@ done
достаточно обновлять серверы по одному. Однако, конечно, чтобы запущенные виртуальные машины достаточно обновлять серверы по одному. Однако, конечно, чтобы запущенные виртуальные машины
начали использовать новую версию клиентской библиотеки, их тоже нужно перезапустить. начали использовать новую версию клиентской библиотеки, их тоже нужно перезапустить.
### 1.7.x -> 1.8.0
Обновляться с версий <= 1.7.x до версий >= 1.8.0 рекомендуется с полной остановкой
сначала клиентов, а затем кластера, так как в 1.8.0 исправлена проблема (неконсистентность
потоков событий от etcd), способная приводить к появлению incomplete объектов в EC-пулах
и, хоть и редко, но даже к повреждению данных при массовых перезапусках OSD. Если вы
обновляетесь без полной остановки - это не значит, что вы обязательно столкнётесь с этой
проблемой, но лучше подстраховаться.
Также, если вы обновляетесь с версии <= 1.7.x до версии >= 1.8.0, НО <= 1.9.0: перезапустите всех
клиентов (процессы виртуальных машин можно перезапустить путём миграции на другой сервер),
иначе они зависнут, когда монитор удалит старый ключ конфигурации PG, что происходит через
24 часа после обновления.
Однако, это исправлено в 1.9.1. Так что, если вы обновляетесь с <= 1.7.x сразу до >= 1.9.1,
вам НЕ нужно сразу перезапускать всех клиентов - они будут работать, как раньше. Минус,
правда, в том, что старый ключ конфигурации PG (`/vitastor/config/pgs`) будет нужно удалить
вам из etcd вручную - после того, как вы убедитесь, что все клиенты перезапущены.
### 1.1.x -> 1.2.0 ### 1.1.x -> 1.2.0
Обновляться с версий <= 1.1.x до версий >= 1.2.0, если вы используете EC n+k и k>=2, Обновляться с версий <= 1.1.x до версий >= 1.2.0, если вы используете EC n+k и k>=2,

View File

@ -16,7 +16,6 @@ It supports the following commands:
- [create](#create) - [create](#create)
- [snap-create](#create) - [snap-create](#create)
- [modify](#modify) - [modify](#modify)
- [dd](#dd)
- [rm](#rm) - [rm](#rm)
- [flatten](#flatten) - [flatten](#flatten)
- [rm-data](#rm-data) - [rm-data](#rm-data)
@ -149,60 +148,19 @@ You should resize file system in the image, if present, before shrinking it.
* `-f|--force` - Proceed with shrinking or setting readwrite flag even if the image has children. * `-f|--force` - Proceed with shrinking or setting readwrite flag even if the image has children.
* `--down-ok` - Proceed with shrinking even if some data will be left on unavailable OSDs. * `--down-ok` - Proceed with shrinking even if some data will be left on unavailable OSDs.
## dd
```
vitastor-cli dd [iimg=<image> | if=<file>] [oimg=<image> | of=<file>] [bs=1M] \
[count=N] [seek/oseek=N] [skip/iseek=M] [iodepth=N] [status=progress] \
[conv=nocreat,noerror,nofsync,trunc,nosparse] [iflag=direct] [oflag=direct,append]
```
Copy data between Vitastor images, files and pipes.
Options can be specified in classic dd style (`key=value`) or like usual (`--key value`).
| <!-- --> | <!-- --> |
|-----------------|-------------------------------------------------------------------------|
| `iimg=<image>` | Copy from Vitastor image `<image>` |
| `if=<file>` | Copy from file `<file>` |
| `oimg=<image>` | Copy to Vitastor image `<image>` |
| `of=<file>` | Copy to file `<file>` |
| `bs=1M` | Set copy block size |
| `count=N` | Copy only N input blocks. If N ends in B it counts bytes, not blocks |
| `seek/oseek=N` | Skip N output blocks. If N ends in B it counts bytes, not blocks |
| `skip/iseek=N` | Skip N input blocks. If N ends in B it counts bytes, not blocks |
| `iodepth=N` | Send N reads or writes in parallel (default 4) |
| `status=LEVEL` | The LEVEL of information to print to stderr: none/noxfer/progress |
| `size=N` | Specify size for the created output file/image (defaults to input size) |
| `iflag=direct` | For input files only: use direct I/O |
| `oflag=direct` | For output files only: use direct I/O |
| `oflag=append` | For files only: append to output file |
| `conv=nocreat` | Do not create output file/image |
| `conv=trunc` | Truncate output file/image |
| `conv=noerror` | Continue copying after errors |
| `conv=nofsync` | Do not call fsync before finishing (default behaviour is fsync) |
| `conv=nosparse` | Write all output blocks including all-zero blocks |
## rm ## rm
`vitastor-cli rm <from> [<to>] [--writers-stopped] [--down-ok]` `vitastor-cli rm <from> [<to>] [--writers-stopped] [--down-ok]`
`vitastor-cli rm (--exact|--matching) <glob> ...` Remove `<from>` or all layers between `<from>` and `<to>` (`<to>` must be a child of `<from>`),
rebasing all their children accordingly. --writers-stopped allows merging to be a bit
more effective in case of a single 'slim' read-write child and 'fat' removed parent:
the child is merged into parent and parent is renamed to child in that case.
In other cases parent layers are always merged into children.
Remove layer(s) and rebase all their children accordingly. Other options:
In the first form, remove `<from>` or layers between `<from>` and its child `<to>`. * `--down-ok` - Continue deletion/merging even if some data will be left on unavailable OSDs.
In the second form, remove all images with exact or pattern-matched names.
Options:
* `--writers-stopped` allows optimised removal in case of a single 'slim' read-write
child and 'fat' removed parent: the child is merged into parent and parent is renamed
to child in that case. In other cases parent layers are always merged into children.
* `--exact` - remove multiple images with names matching given glob patterns.
* `--matching` - remove multiple images with given names
* `--down-ok` - continue deletion/merging even if some data will be left on unavailable OSDs.
## flatten ## flatten

View File

@ -17,7 +17,6 @@ vitastor-cli - интерфейс командной строки для адм
- [create](#create) - [create](#create)
- [snap-create](#create) - [snap-create](#create)
- [modify](#modify) - [modify](#modify)
- [dd](#dd)
- [rm](#rm) - [rm](#rm)
- [flatten](#flatten) - [flatten](#flatten)
- [rm-data](#rm-data) - [rm-data](#rm-data)
@ -152,61 +151,23 @@ vitastor-cli snap-create [-p|--pool <id|name>] <image>@<snapshot>
* `-f|--force` - Разрешить уменьшение или перевод в чтение-запись образа, у которого есть клоны. * `-f|--force` - Разрешить уменьшение или перевод в чтение-запись образа, у которого есть клоны.
* `--down-ok` - Разрешить уменьшение, даже если часть данных останется неудалённой на недоступных OSD. * `--down-ok` - Разрешить уменьшение, даже если часть данных останется неудалённой на недоступных OSD.
## dd
```
vitastor-cli dd [iimg=<image> | if=<file>] [oimg=<image> | of=<file>] [bs=1M] \
[count=N] [seek/oseek=N] [skip/iseek=M] [iodepth=N] [status=progress] \
[conv=nocreat,noerror,nofsync,trunc,nosparse] [iflag=direct] [oflag=direct,append]
```
Копировать данные между образами Vitastor, файлами и каналами.
Опции можно передавать в классическом стиле dd (`key=value`) или как обычно (`--key value`).
| <!-- --> | <!-- --> |
|-----------------|-------------------------------------------------------------------------|
| `iimg=<image>` | Копировать из образа Vitastor `<image>` |
| `if=<file>` | Копировать из файла `<file>` |
| `oimg=<image>` | Копировать в образ Vitastor `<image>` |
| `of=<file>` | Копировать в файл `<file>` |
| `bs=1M` | Задать размер блока копирования |
| `count=N` | Копировать не более N блоков. Если N заканчивается на B - то N байт. |
| `seek/oseek=N` | Пропустить N выходных блоков. Если N заканчивается на B - то N байт. |
| `skip/iseek=N` | Пропустить N входных блоков. Если N заканчивается на B - то N байт. |
| `iodepth=N` | Отправлять N чтений/записей параллельно (по умолчанию 4). |
| `status=LEVEL` | Уровень вывода в консоль: none/noxfer/progress |
| `size=N` | Задать размер выходного файла/образа (по умолчанию равен размеру входа).|
| `iflag=direct` | Только для входного файла: использовать прямой ввод-вывод |
| `oflag=direct` | Только для выходного файла: использовать прямой ввод-вывод |
| `oflag=append` | Только для файлов: дописывать в конец выходного файла |
| `conv=nocreat` | Не создавать выходной файл/образ |
| `conv=trunc` | Обрезать выходной файл/образ до размера входа |
| `conv=noerror` | Продолжать копирование после ошибок |
| `conv=nofsync` | Не вызывать fsync перед завершением |
| `conv=nosparse` | Записывать все выходные блоки, включая пустые |
## rm ## rm
`vitastor-cli rm <from> [<to>] [--writers-stopped] [--down-ok]` `vitastor-cli rm <from> [<to>] [--writers-stopped] [--down-ok]`
`vitastor-cli rm (--exact|--matching) <glob> ...` Удалить образ `<from>` или все слои от `<from>` до `<to>` (`<to>` должен быть дочерним
образом `<from>`), одновременно меняя родительские образы их клонов (если таковые есть).
Удалить образ(ы), корректно перебазируя их дочерние образы. `--writers-stopped` позволяет чуть более эффективно удалять образы в частом случае, когда
у удаляемой цепочки есть только один дочерний образ, содержащий небольшой объём данных.
В этом случае дочерний образ вливается в родительский и удаляется, а родительский
переименовывается в дочерний.
В первой форме удаляет один образ `<from>` или все слои между `<from>` и его дочерним `<to>`. В других случаях родительские слои вливаются в дочерние.
Во второй форме, удаляет все образы с точными именами или именами, подходящими под шаблон(ы). Другие опции:
Опции: * `--down-ok` - Продолжать удаление/слияние, даже если часть данных останется неудалённой на недоступных OSD.
* `--writers-stopped` позволяет чуть более эффективно удалять образы в частом случае, когда
у удаляемой цепочки есть только один дочерний образ, содержащий небольшой объём данных.
В этом случае дочерний образ вливается в родительский и удаляется, а родительский
переименовывается в дочерний.
* `--exact` - удалить все образы с именами, подходящими под переданные glob-шаблоны.
* `--matching` - удалить все образы с точно заданными именами.
* `--down-ok` - продолжать удаление/слияние, даже если часть данных останется неудалённой на недоступных OSD.
## flatten ## flatten

View File

@ -13,7 +13,6 @@ It supports the following commands:
- [prepare](#prepare) - [prepare](#prepare)
- [upgrade-simple](#upgrade-simple) - [upgrade-simple](#upgrade-simple)
- [resize](#resize) - [resize](#resize)
- [raw-resize](#raw-resize)
- [start/stop/restart/enable/disable](#start/stop/restart/enable/disable) - [start/stop/restart/enable/disable](#start/stop/restart/enable/disable)
- [purge](#purge) - [purge](#purge)
- [read-sb](#read-sb) - [read-sb](#read-sb)
@ -51,16 +50,12 @@ Options (automatic mode):
--osd_per_disk <N> --osd_per_disk <N>
Create <N> OSDs on each disk (default 1) Create <N> OSDs on each disk (default 1)
--hybrid --hybrid
Prepare hybrid (HDD+SSD, NVMe+SATA or etc) OSDs using provided devices. By default, Prepare hybrid (HDD+SSD) OSDs using provided devices. SSDs will be used for
any passed SSDs will be used for journals and metadata, HDDs will be used for data, journals and metadata, HDDs will be used for data. Partitions for journals and
but you can override this behaviour with --fast-devices option. Journal and metadata metadata will be created automatically. Whether disks are SSD or HDD is decided
partitions will be created automatically. In the default mode, SSD and HDD disks by the `/sys/block/.../queue/rotational` flag. In hybrid mode, default object
are distinguished by the `/sys/block/.../queue/rotational` flag. When HDDs are used size is 1 MB instead of 128 KB, default journal size is 1 GB instead of 32 MB,
for data in hybrid mode, default block_size is 1 MB instead of 128 KB, default journal and throttle_small_writes is enabled by default.
size is 1 GB instead of 32 MB, and throttle_small_writes is enabled by default.
--fast-devices /dev/nvmeX,/dev/nvmeY
In --hybrid mode, use these devices for journal and metadata instead of auto-detecting
and extracting them from the main [devices...] list.
--disable_data_fsync auto --disable_data_fsync auto
Disable data device cache and fsync (1/yes/true = on, default auto) Disable data device cache and fsync (1/yes/true = on, default auto)
--disable_meta_fsync auto --disable_meta_fsync auto
@ -132,49 +127,25 @@ Requires the `sfdisk` utility.
## resize ## resize
`vitastor-disk resize <osd_num>|<osd_device> [OPTIONS]` `vitastor-disk resize <ALL_OSD_PARAMETERS> <NEW_LAYOUT> [--iodepth 32]`
Resize data area and/or move journal and metadata: Resize data area and/or rewrite/move journal and metadata.
| <!-- --> | <!-- --> |
|---------------------------|----------------------------------------|
| `--move-journal TARGET` | move journal to `TARGET` |
| `--move-meta TARGET` | move metadata to `TARGET` |
| `--journal-size NEW_SIZE` | resize journal to `NEW_SIZE` |
| `--data-size NEW_SIZE` | resize data device to `NEW_SIZE` |
| `--dry-run` | only show new layout, do not apply it |
`NEW_SIZE` may include k/m/g/t suffixes.
`TARGET` may be one of:
| <!-- --> | <!-- --> |
|----------------|--------------------------------------------------------------------------|
| `<partition>` | move journal/metadata to an existing GPT partition |
| `<raw_device>` | create a GPT partition on `<raw_device>` and move journal/metadata to it |
| `""` | (empty string) move journal/metadata back to the data device |
## raw-resize
`vitastor-disk raw-resize <ALL_OSD_PARAMETERS> <NEW_LAYOUT> [--iodepth 32]`
Resize data area and/or rewrite/move journal and metadata (manual format).
`ALL_OSD_PARAMETERS` must include all (at least all disk-related) `ALL_OSD_PARAMETERS` must include all (at least all disk-related)
parameters from OSD command line (i.e. from systemd unit or superblock). parameters from OSD command line (i.e. from systemd unit or superblock).
`NEW_LAYOUT` may include new disk layout parameters: `NEW_LAYOUT` may include new disk layout parameters:
| <!-- --> | <!-- --> | ```
|-----------------------------|-------------------------------------------| --new_data_offset SIZE resize data area so it starts at SIZE
| `--new_data_offset SIZE` | resize data area so it starts at `SIZE` | --new_data_len SIZE resize data area to SIZE bytes
| `--new_data_len SIZE` | resize data area to `SIZE` bytes | --new_meta_device PATH use PATH for new metadata
| `--new_meta_device PATH` | use `PATH` for new metadata | --new_meta_offset SIZE make new metadata area start at SIZE
| `--new_meta_offset SIZE` | make new metadata area start at `SIZE` | --new_meta_len SIZE make new metadata area SIZE bytes long
| `--new_meta_len SIZE` | make new metadata area `SIZE` bytes long | --new_journal_device PATH use PATH for new journal
| `--new_journal_device PATH` | use `PATH` for new journal | --new_journal_offset SIZE make new journal area start at SIZE
| `--new_journal_offset SIZE` | make new journal area start at `SIZE` | --new_journal_len SIZE make new journal area SIZE bytes long
| `--new_journal_len SIZE` | make new journal area `SIZE` bytes long | ```
SIZE may include k/m/g/t suffixes. If any of the new layout parameter SIZE may include k/m/g/t suffixes. If any of the new layout parameter
options are not specified, old values will be used. options are not specified, old values will be used.
@ -246,14 +217,10 @@ Intended for use from startup scripts (i.e. from systemd units).
## dump-journal ## dump-journal
`vitastor-disk dump-journal [OPTIONS] <osd_device>`
`vitastor-disk dump-journal [OPTIONS] <journal_file> <journal_block_size> <offset> <size>` `vitastor-disk dump-journal [OPTIONS] <journal_file> <journal_block_size> <offset> <size>`
Dump journal in human-readable or JSON (if `--json` is specified) format. Dump journal in human-readable or JSON (if `--json` is specified) format.
You can specify any OSD device (data, metadata or journal), or the layout manually.
Options: Options:
``` ```
@ -266,35 +233,23 @@ Options:
## write-journal ## write-journal
`vitastor-disk write-journal <osd_device>`
`vitastor-disk write-journal <journal_file> <journal_block_size> <bitmap_size> <offset> <size>` `vitastor-disk write-journal <journal_file> <journal_block_size> <bitmap_size> <offset> <size>`
Write journal from JSON taken from standard input in the same format as produced by Write journal from JSON taken from standard input in the same format as produced by
`dump-journal --json --format data`. `dump-journal --json --format data`.
You can specify any OSD device (data, metadata or journal), or the layout manually.
## dump-meta ## dump-meta
`vitastor-disk dump-meta <osd_device>`
`vitastor-disk dump-meta <meta_file> <meta_block_size> <offset> <size>` `vitastor-disk dump-meta <meta_file> <meta_block_size> <offset> <size>`
Dump metadata in JSON format. Dump metadata in JSON format.
You can specify any OSD device (data, metadata or journal), or the layout manually.
## write-meta ## write-meta
`vitastor-disk write-meta <osd_device>`
`vitastor-disk write-meta <meta_file> <offset> <size>` `vitastor-disk write-meta <meta_file> <offset> <size>`
Write metadata from JSON taken from standard input in the same format as produced by `dump-meta`. Write metadata from JSON taken from standard input in the same format as produced by `dump-meta`.
You can specify any OSD device (data, metadata or journal), or the layout manually.
## simple-offsets ## simple-offsets
`vitastor-disk simple-offsets <device>` `vitastor-disk simple-offsets <device>`

View File

@ -13,7 +13,6 @@ vitastor-disk - инструмент командной строки для уп
- [prepare](#prepare) - [prepare](#prepare)
- [upgrade-simple](#upgrade-simple) - [upgrade-simple](#upgrade-simple)
- [resize](#resize) - [resize](#resize)
- [raw-resize](#raw-resize)
- [start/stop/restart/enable/disable](#start/stop/restart/enable/disable) - [start/stop/restart/enable/disable](#start/stop/restart/enable/disable)
- [purge](#purge) - [purge](#purge)
- [read-sb](#read-sb) - [read-sb](#read-sb)
@ -51,17 +50,12 @@ vitastor-disk - инструмент командной строки для уп
--osd_per_disk <N> --osd_per_disk <N>
Создавать по несколько (<N>) OSD на каждом диске (по умолчанию 1) Создавать по несколько (<N>) OSD на каждом диске (по умолчанию 1)
--hybrid --hybrid
Инициализировать гибридные (HDD+SSD, NVMe+SATA и т.п.) OSD на указанных дисках. Инициализировать гибридные (HDD+SSD) OSD на указанных дисках. SSD будут
По умолчанию, SSD будут использованы для журналов и метаданных, а HDD - для данных, использованы для журналов и метаданных, а HDD - для данных. Разделы для журналов
но вы можете поменять это поведение опцией --fast-devices. Разделы для журналов и метаданных будут созданы автоматически. Является ли диск SSD или HDD, определяется
и метаданных будут созданы автоматически. В режиме по умолчанию SSD и HDD-диски по флагу `/sys/block/.../queue/rotational`. В гибридном режиме по умолчанию
различаются по флагу `/sys/block/.../queue/rotational`. Когда в гибридном режиме используется размер объекта 1 МБ вместо 128 КБ, размер журнала 1 ГБ вместо 32 МБ
для данных используются HDD, по умолчанию размер блока устанавливается 1 МБ вместо и включённый throttle_small_writes.
128 КБ, размер журнала 1 ГБ вместо 32 МБ, и throttle_small_writes включается по
умолчанию.
--fast-devices /dev/nvmeX,/dev/nvmeY
Использовать данные диски для журналов и метаданных в гибридном режиме вместо их
автоопределения и извлечения из основного списка [devices...].
--disable_data_fsync auto --disable_data_fsync auto
Отключать кэш и fsync-и для устройств данных. (1/yes/true = да, по умолчанию автоопределение) Отключать кэш и fsync-и для устройств данных. (1/yes/true = да, по умолчанию автоопределение)
--disable_meta_fsync auto --disable_meta_fsync auto
@ -135,51 +129,27 @@ throttle_target_mbs, throttle_target_parallelism, throttle_threshold_us.
## resize ## resize
`vitastor-disk resize <osd_num>|<osd_device> [OPTIONS]` `vitastor-disk resize <ALL_OSD_PARAMETERS> <NEW_LAYOUT> [--iodepth 32]`
Изменить размер области данных и/или переместить журнал и метаданные: Изменить размер области данных и/или переместить журнал и метаданные.
| <!-- --> | <!-- --> | В `ALL_OSD_PARAMETERS` нужно указать все относящиеся к диску параметры OSD
|-------------------------------|------------------------------------------------|
| `--move-journal ЦЕЛЬ` | переместить журнал на `ЦЕЛЬ` |
| `--move-meta ЦЕЛЬ` | переместить метаданные на `ЦЕЛЬ` |
| `--journal-size НОВЫЙ_РАЗМЕР` | изменить размер журнала на `НОВЫЙ_РАЗМЕР` |
| `--data-size НОВЫЙ_РАЗМЕР` | изменить размер диска данных на `НОВЫЙ_РАЗМЕР` |
| `--dry-run` | показать новые параметры, но не применять их |
`НОВЫЙ_РАЗМЕР` может быть указан с суффиксами k/m/g/t (кило/мега/гига/терабайт).
`ЦЕЛЬ` может быть одним из:
| <!-- --> | <!-- --> |
|-----------------|-------------------------------------------------------------------------------------|
| `<раздел>` | переместить журнал/метаданные на существующий GPT-раздел |
| `<полный_диск>` | создать GPT-раздел на диске `<полный_диск>` и переместить журнал/метаданные на него |
| `""` | (пустая строка) переместить журнал/метаданные обратно на диск данных |
## raw-resize
`vitastor-disk raw-resize <ВСЕАРАМЕТРЫ_OSD> <НОВЫЕ_РАЗМЕРЫ> [--iodepth 32]`
Изменить размер области данных и/или переместить журнал и метаданные (ручной формат).
В `ВСЕАРАМЕТРЫ_OSD` нужно указать все относящиеся к диску параметры OSD
из суперблока OSD или из файла сервиса systemd (в старых версиях). из суперблока OSD или из файла сервиса systemd (в старых версиях).
В `НОВЫЕ_РАЗМЕРЫ` нужно указать новые параметры расположения данных: В `NEW_LAYOUT` нужно указать новые параметры расположения данных:
| <!-- --> | <!-- --> | ```
|-------------------------------|-------------------------------------------------------| --new_data_offset РАЗМЕР сдвинуть начало области данных на РАЗМЕР байт
| `--new_data_offset РАЗМЕР` | сдвинуть начало области данных на `РАЗМЕР` байт | --new_data_len РАЗМЕР изменить размер области данных до РАЗМЕР байт
| `--new_data_len РАЗМЕР` | изменить размер области данных до `РАЗМЕР` байт | --new_meta_device ПУТЬ использовать ПУТЬ как новое устройство метаданных
| `--new_meta_device ПУТЬ` | использовать `ПУТЬ` как новое устройство метаданных | --new_meta_offset РАЗМЕР разместить новые метаданные по смещению РАЗМЕР байт
| `--new_meta_offset РАЗМЕР` | разместить новые метаданные по смещению `РАЗМЕР` байт | --new_meta_len РАЗМЕР сделать новые метаданные размером РАЗМЕР байт
| `--new_meta_len РАЗМЕР` | сделать новые метаданные размером `РАЗМЕР` байт | --new_journal_device ПУТЬ использовать ПУТЬ как новое устройство журнала
| `--new_journal_device ПУТЬ` | использовать `ПУТЬ` как новое устройство журнала | --new_journal_offset РАЗМЕР разместить новый журнал по смещению РАЗМЕР байт
| `--new_journal_offset РАЗМЕР` | разместить новый журнал по смещению `РАЗМЕР` байт | --new_journal_len РАЗМЕР сделать новый журнал размером РАЗМЕР байт
| `--new_journal_len РАЗМЕР` | сделать новый журнал размером `РАЗМЕР` байт | ```
`РАЗМЕР` может быть указан с суффиксами k/m/g/t. Если любой из новых параметров РАЗМЕР может быть указан с суффиксами k/m/g/t. Если любой из новых параметров
расположения не указан, он принимается равным старому значению. расположения не указан, он принимается равным старому значению.
## start/stop/restart/enable/disable ## start/stop/restart/enable/disable
@ -254,15 +224,10 @@ OSD отключены fsync-и.
## dump-journal ## dump-journal
`vitastor-disk dump-journal <osd_device>`
`vitastor-disk dump-journal [OPTIONS] <journal_file> <journal_block_size> <offset> <size>` `vitastor-disk dump-journal [OPTIONS] <journal_file> <journal_block_size> <offset> <size>`
Вывести журнал в человекочитаемом или в JSON (с опцией `--json`) виде. Вывести журнал в человекочитаемом или в JSON (с опцией `--json`) виде.
Вы можете указать любой раздел OSD - данных, журнала или метаданных - либо указать все
параметры расположения вручную.
Опции: Опции:
``` ```
@ -275,37 +240,22 @@ OSD отключены fsync-и.
## write-journal ## write-journal
`vitastor-disk write-journal <osd_device>`
`vitastor-disk write-journal <journal_file> <journal_block_size> <bitmap_size> <offset> <size>` `vitastor-disk write-journal <journal_file> <journal_block_size> <bitmap_size> <offset> <size>`
Записать журнал из JSON со стандартного ввода в формате, аналогичном `dump-journal --json --format data`. Записать журнал из JSON со стандартного ввода в формате, аналогичном `dump-journal --json --format data`.
Вы можете указать любой раздел OSD - данных, журнала или метаданных - либо указать все
параметры расположения вручную.
## dump-meta ## dump-meta
`vitastor-disk dump-meta <osd_device>`
`vitastor-disk dump-meta <meta_file> <meta_block_size> <offset> <size>` `vitastor-disk dump-meta <meta_file> <meta_block_size> <offset> <size>`
Вывести метаданные в формате JSON. Вывести метаданные в формате JSON.
Вы можете указать любой раздел OSD - данных, журнала или метаданных - либо указать все
параметры расположения вручную.
## write-meta ## write-meta
`vitastor-disk write-meta <osd_device>`
`vitastor-disk write-meta <meta_file> <offset> <size>` `vitastor-disk write-meta <meta_file> <offset> <size>`
Записать метаданные из JSON со стандартного ввода в формате, аналогичном `dump-meta`. Записать метаданные из JSON со стандартного ввода в формате, аналогичном `dump-meta`.
Вы можете указать любой раздел OSD - данных, журнала или метаданных - либо указать все
параметры расположения вручную.
## simple-offsets ## simple-offsets
`vitastor-disk simple-offsets <device>` `vitastor-disk simple-offsets <device>`

View File

@ -157,16 +157,16 @@ behind. Defragmentation removes garbage and moves data still in use to new volum
Options: Options:
| <!-- --> | <!-- --> | | <!-- --> | <!-- --> |
|----------------------------|------------------------------------------------------------------------ | |--------------------------|------------------------------------------------------------------------ |
| `--volume_untouched 86400` | Defragment volumes last appended to at least this number of seconds ago | | --volume_untouched 86400 | Defragment volumes last appended to at least this number of seconds ago |
| `--defrag_percent 50` | Defragment volumes with at least this % of removed data | | --defrag_percent 50 | Defragment volumes with at least this % of removed data |
| `--defrag_block_count 16` | Read this number of pool blocks at once during defrag | | --defrag_block_count 16 | Read this number of pool blocks at once during defrag |
| `--defrag_iodepth 16` | Move up to this number of files in parallel during defrag | | --defrag_iodepth 16 | Move up to this number of files in parallel during defrag |
| `--trace` | Print verbose defragmentation status | | --trace | Print verbose defragmentation status |
| `--dry-run` | Skip modifications, only print status | | --dry-run | Skip modifications, only print status |
| `--recalc-stats` | Recalculate all volume statistics | | --recalc-stats | Recalculate all volume statistics |
| `--include-empty` | Include old and empty volumes; make sure to restart NFS servers before using it | | --include-empty | Include old and empty volumes; make sure to restart NFS servers before using it |
| `--no-rm` | Move, but do not delete data | | --no-rm | Move, but do not delete data |
## Common options ## Common options

View File

@ -165,16 +165,16 @@ JSON-формате :-). Для инспекции содержимого БД
Опции: Опции:
| <!-- --> | <!-- --> | | <!-- --> | <!-- --> |
|----------------------------|------------------------------------------------------------------------ | |--------------------------|------------------------------------------------------------------------ |
| `--volume_untouched 86400` | Дефрагментировать только тома, в которые уже не писали это число секунд | | --volume_untouched 86400 | Дефрагментировать только тома, в которые уже не писали это число секунд |
| `--defrag_percent 50` | Дефрагментировать только тома, в которых этот % данных удалён | | --defrag_percent 50 | Дефрагментировать только тома, в которых этот % данных удалён |
| `--defrag_block_count 16` | Читать это количество блоков пула за один раз | | --defrag_block_count 16 | Читать это количество блоков пула за один раз |
| `--defrag_iodepth 16` | Перемещать одновременно до этого числа файлов | | --defrag_iodepth 16 | Перемещать одновременно до этого числа файлов |
| `--trace` | Печатать детальную статистику дефрагментации | | --trace | Печатать детальную статистику дефрагментации |
| `--dry-run` | Не производить никаких изменений, только описать выполняемые действия | | --dry-run | Не производить никаких изменений, только описать выполняемые действия |
| `--recalc-stats` | Пересчитать и сохранить статистику всех томов | | --recalc-stats | Пересчитать и сохранить статистику всех томов |
| `--include-empty` | Дефрагментировать старые и пустые тома; обязательно перезапустите NFS-сервера после использования этой опции | | --include-empty | Дефрагментировать старые и пустые тома; обязательно перезапустите NFS-сервера после использования этой опции |
| `--no-rm` | Перемещать, но не удалять данные | | --no-rm | Перемещать, но не удалять данные |
## Общие опции ## Общие опции

View File

@ -151,9 +151,9 @@ Example performance comparison:
To try VDUSE you need at least Linux 5.15, built with VDUSE support To try VDUSE you need at least Linux 5.15, built with VDUSE support
(CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m). (CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m).
Debian Linux kernels had these options disabled until 6.6, so make sure you install a newer kernel Debian Linux kernels have these options disabled by now, so if you want to try it on Debian,
(from bookworm-backports, trixie or newer Debian version) if you want to try VDUSE. You can also use a kernel from Ubuntu [kernel-ppa/mainline](https://kernel.ubuntu.com/~kernel-ppa/mainline/), Proxmox,
build modules for an existing kernel manually: or build modules for Debian kernel manually:
``` ```
mkdir build mkdir build

View File

@ -154,9 +154,9 @@ VDUSE - на данный момент лучший интерфейс для п
Чтобы попробовать VDUSE, вам нужно ядро Linux как минимум версии 5.15, собранное с поддержкой Чтобы попробовать VDUSE, вам нужно ядро Linux как минимум версии 5.15, собранное с поддержкой
VDUSE (CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m). VDUSE (CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m).
В ядрах в Debian Linux эти опции включены, только начиная с 6.6, так что установите свежее ядро В ядрах в Debian Linux поддержка пока отключена по умолчанию, так что чтобы попробовать VDUSE
из bookworm-backports, trixie или из более новой версии Debian, если хотите попробовать VDUSE. на Debian, поставьте ядро из Ubuntu [kernel-ppa/mainline](https://kernel.ubuntu.com/~kernel-ppa/mainline/),
Либо же вы можете самостоятельно собрать модули для установленного ядра: из Proxmox или соберите модули для ядра Debian вручную:
``` ```
mkdir build mkdir build

View File

@ -232,7 +232,6 @@ class EtcdAdapter
async become_master() async become_master()
{ {
const state = { ...this.mon.get_mon_state(), id: ''+this.mon.etcd_lease_id }; const state = { ...this.mon.get_mon_state(), id: ''+this.mon.etcd_lease_id };
console.log('Waiting to become master');
// eslint-disable-next-line no-constant-condition // eslint-disable-next-line no-constant-condition
while (1) while (1)
{ {
@ -244,6 +243,7 @@ class EtcdAdapter
{ {
break; break;
} }
console.log('Waiting to become master');
await new Promise(ok => setTimeout(ok, this.mon.config.etcd_start_timeout)); await new Promise(ok => setTimeout(ok, this.mon.config.etcd_start_timeout));
} }
console.log('Became master'); console.log('Became master');

View File

@ -56,7 +56,6 @@ const etcd_tree = {
osd_out_time: 600, // seconds. min: 0 osd_out_time: 600, // seconds. min: 0
placement_levels: { datacenter: 1, rack: 2, host: 3, osd: 4, ... }, placement_levels: { datacenter: 1, rack: 2, host: 3, osd: 4, ... },
use_old_pg_combinator: false, use_old_pg_combinator: false,
osd_backfillfull_ratio: 0.99,
// client and osd // client and osd
tcp_header_buffer_size: 65536, tcp_header_buffer_size: 65536,
use_sync_send_recv: false, use_sync_send_recv: false,

View File

@ -74,7 +74,6 @@ class Mon
this.state = JSON.parse(JSON.stringify(etcd_tree)); this.state = JSON.parse(JSON.stringify(etcd_tree));
this.prev_stats = { osd_stats: {}, osd_diff: {} }; this.prev_stats = { osd_stats: {}, osd_diff: {} };
this.recheck_pgs_active = false; this.recheck_pgs_active = false;
this.updating_total_stats = false;
this.watcher_active = false; this.watcher_active = false;
this.old_pg_config = false; this.old_pg_config = false;
this.old_pg_stats_seen = false; this.old_pg_stats_seen = false;
@ -219,10 +218,6 @@ class Mon
} }
else if (key != '/stats' && key.substr(0, 13) != '/inode/stats/') else if (key != '/stats' && key.substr(0, 13) != '/inode/stats/')
{ {
if (key == '/config/pgs' && !kv.value)
{
this.old_pg_config = false;
}
changed = true; changed = true;
} }
if (this.config.verbose) if (this.config.verbose)
@ -427,6 +422,30 @@ class Mon
throw new Error('Failed to duplicate old PG config to new PG config'); throw new Error('Failed to duplicate old PG config to new PG config');
} }
this.old_pg_config = true; this.old_pg_config = true;
this.old_pg_config_timer = setInterval(() => this.check_clear_old_config().catch(console.error),
this.config.old_pg_config_clear_interval||3600000);
}
}
async check_clear_old_config()
{
if (this.old_pg_config && this.old_pg_stats_seen)
{
this.old_pg_stats_seen = false;
return;
}
if (this.old_pg_config)
{
await this.etcd.etcd_call('/kv/txn', { success: [
{ requestDeleteRange: { key: b64(this.config.etcd_prefix+'/config/pgs') } },
{ requestDeleteRange: { key: b64(this.config.etcd_prefix+'/pg/stats/'), range_end: b64(this.config.etcd_prefix+'/pg/stats0') } },
] }, this.config.etcd_mon_timeout, this.config.etcd_mon_retries);
this.old_pg_config = false;
}
if (this.old_pg_config_timer)
{
clearInterval(this.old_pg_config_timer);
this.old_pg_config_timer = null;
} }
} }
@ -568,7 +587,6 @@ class Mon
async apply_pool_pgs(results, up_osds, osd_tree, tree_hash) async apply_pool_pgs(results, up_osds, osd_tree, tree_hash)
{ {
const etcd_request = { compare: [], success: [] };
for (const pool_id in (this.state.pg.config||{}).items||{}) for (const pool_id in (this.state.pg.config||{}).items||{})
{ {
// We should stop all PGs when deleting a pool or changing its PG count // We should stop all PGs when deleting a pool or changing its PG count
@ -581,24 +599,9 @@ class Mon
return false; return false;
} }
} }
if (!this.state.config.pools[pool_id])
{
// Delete PG history and stats of the deleted pool
etcd_request.success.push({ requestDeleteRange: {
key: b64(this.config.etcd_prefix+'/pg/history/'+pool_id+'/'),
range_end: b64(this.config.etcd_prefix+'/pg/history/'+pool_id+'0'),
} });
etcd_request.success.push({ requestDeleteRange: {
key: b64(this.config.etcd_prefix+'/pg/stats/'+pool_id+'/'),
range_end: b64(this.config.etcd_prefix+'/pg/stats/'+pool_id+'0'),
} });
etcd_request.success.push({ requestDeleteRange: {
key: b64(this.config.etcd_prefix+'/pgstats/'+pool_id+'/'),
range_end: b64(this.config.etcd_prefix+'/pgstats/'+pool_id+'0'),
} });
}
} }
const new_pg_config = JSON.parse(JSON.stringify(this.state.pg.config)); const new_pg_config = JSON.parse(JSON.stringify(this.state.pg.config));
const etcd_request = { compare: [], success: [] };
for (const pool_id in (new_pg_config||{}).items||{}) for (const pool_id in (new_pg_config||{}).items||{})
{ {
if (!this.state.config.pools[pool_id]) if (!this.state.config.pools[pool_id])
@ -659,19 +662,7 @@ class Mon
this.etcd_watch_revision, pool_id, up_osds, osd_tree, real_prev_pgs, pool_res.pgs, pg_history); this.etcd_watch_revision, pool_id, up_osds, osd_tree, real_prev_pgs, pool_res.pgs, pg_history);
} }
new_pg_config.hash = tree_hash; new_pg_config.hash = tree_hash;
const { backfillfull_pools, backfillfull_osds } = sum_object_counts( return await this.save_pg_config(new_pg_config, etcd_request);
{ ...this.state, pg: { ...this.state.pg, config: new_pg_config } }, this.config
);
if (backfillfull_pools.join(',') != ((this.state.pg.config||{}).backfillfull_pools||[]).join(','))
{
this.log_backfillfull(backfillfull_osds, backfillfull_pools);
}
new_pg_config.backfillfull_pools = backfillfull_pools.length ? backfillfull_pools : undefined;
if (!await this.save_pg_config(new_pg_config, etcd_request))
{
return false;
}
return true;
} }
async save_pg_config(new_pg_config, etcd_request = { compare: [], success: [] }) async save_pg_config(new_pg_config, etcd_request = { compare: [], success: [] })
@ -743,7 +734,7 @@ class Mon
async update_total_stats() async update_total_stats()
{ {
const txn = []; const txn = [];
const { object_counts, object_bytes, backfillfull_pools, backfillfull_osds } = sum_object_counts(this.state, this.config); const { object_counts, object_bytes } = sum_object_counts(this.state, this.config);
let stats = sum_op_stats(this.state.osd, this.prev_stats); let stats = sum_op_stats(this.state.osd, this.prev_stats);
let { inode_stats, seen_pools } = sum_inode_stats(this.state, this.prev_stats); let { inode_stats, seen_pools } = sum_inode_stats(this.state, this.prev_stats);
stats.object_counts = object_counts; stats.object_counts = object_counts;
@ -796,27 +787,6 @@ class Mon
{ {
await this.etcd.etcd_call('/kv/txn', { success: txn }, this.config.etcd_mon_timeout, 0); await this.etcd.etcd_call('/kv/txn', { success: txn }, this.config.etcd_mon_timeout, 0);
} }
if (!this.recheck_pgs_active &&
backfillfull_pools.join(',') != ((this.state.pg.config||{}).backfillfull_pools||[]).join(','))
{
this.log_backfillfull(backfillfull_osds, backfillfull_pools);
const new_pg_config = { ...this.state.pg.config, backfillfull_pools: backfillfull_pools.length ? backfillfull_pools : undefined };
await this.save_pg_config(new_pg_config);
}
}
log_backfillfull(osds, pools)
{
for (const osd in osds)
{
const bf = osds[osd];
console.log('OSD '+osd+' may fill up during rebalance: capacity '+(bf.cap/1024n/1024n)+
' MB, target user data '+(bf.clean/1024n/1024n)+' MB');
}
console.log(
(pools.length ? 'Pool(s) '+pools.join(', ') : 'No pools')+
' are backfillfull now, applying rebalance configuration'
);
} }
schedule_update_stats() schedule_update_stats()
@ -828,21 +798,7 @@ class Mon
this.stats_timer = setTimeout(() => this.stats_timer = setTimeout(() =>
{ {
this.stats_timer = null; this.stats_timer = null;
if (this.updating_total_stats)
{
this.schedule_update_stats();
return;
}
this.updating_total_stats = true;
try
{
this.update_total_stats().catch(console.error); this.update_total_stats().catch(console.error);
}
catch (e)
{
console.error(e);
}
this.updating_total_stats = false;
}, this.config.mon_stats_timeout); }, this.config.mon_stats_timeout);
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "vitastor-mon", "name": "vitastor-mon",
"version": "1.9.3", "version": "1.7.1",
"description": "Vitastor SDS monitor service", "description": "Vitastor SDS monitor service",
"main": "mon-main.js", "main": "mon-main.js",
"scripts": { "scripts": {

View File

@ -109,8 +109,6 @@ function sum_object_counts(state, global_config)
pgstats[pool_id] = { ...(state.pg.stats[pool_id] || {}), ...(pgstats[pool_id] || {}) }; pgstats[pool_id] = { ...(state.pg.stats[pool_id] || {}), ...(pgstats[pool_id] || {}) };
} }
} }
const pool_per_osd = {};
const clean_per_osd = {};
for (const pool_id in pgstats) for (const pool_id in pgstats)
{ {
let object_size = 0; let object_size = 0;
@ -145,45 +143,10 @@ function sum_object_counts(state, global_config)
object_bytes[k] += BigInt(st[k+'_count']) * object_size; object_bytes[k] += BigInt(st[k+'_count']) * object_size;
} }
} }
if (st.object_count)
{
for (const pg_osd of (((state.pg.config.items||{})[pool_id]||{})[pg_num]||{}).osd_set||[])
{
if (!(pg_osd in clean_per_osd))
{
clean_per_osd[pg_osd] = 0n;
}
clean_per_osd[pg_osd] += BigInt(st.object_count);
pool_per_osd[pg_osd] = pool_per_osd[pg_osd]||{};
pool_per_osd[pg_osd][pool_id] = true;
} }
} }
} }
} return { object_counts, object_bytes };
}
// If clean_per_osd[osd] is larger than osd capacity then it will fill up during rebalance
let backfillfull_pools = {};
let backfillfull_osds = {};
for (const osd in clean_per_osd)
{
const st = state.osd.stats[osd];
if (!st || !st.size || !st.data_block_size)
{
continue;
}
let cap = BigInt(st.size)/BigInt(st.data_block_size);
cap = cap * BigInt((global_config.osd_backfillfull_ratio||0.99)*1000000) / 1000000n;
if (cap < clean_per_osd[osd])
{
backfillfull_osds[osd] = { cap: BigInt(st.size), clean: clean_per_osd[osd]*BigInt(st.data_block_size) };
for (const pool_id in pool_per_osd[osd])
{
backfillfull_pools[pool_id] = true;
}
}
}
backfillfull_pools = Object.keys(backfillfull_pools).sort();
return { object_counts, object_bytes, backfillfull_pools, backfillfull_osds };
} }
// sum_inode_stats(this.state, this.prev_stats) // sum_inode_stats(this.state, this.prev_stats)

View File

@ -11,10 +11,10 @@
#define ERRORF(format, ...) fprintf(stderr, format "\n", __VA_ARGS__); #define ERRORF(format, ...) fprintf(stderr, format "\n", __VA_ARGS__);
//#define TRACEF(format, ...) fprintf(stderr, format "\n", __VA_ARGS__); #define TRACEF(format, ...) fprintf(stderr, format "\n", __VA_ARGS__);
//#define TRACE(msg) fprintf(stderr, "%s\n", msg); #define TRACE(msg) fprintf(stderr, "%s\n", msg);
#define TRACEF(format, ...) ; //#define TRACEF(format, arg) ;
#define TRACE(msg) ; //#define TRACE(msg) ;
#endif #endif

View File

@ -10,7 +10,7 @@
'<!(node -e "require(\'nan\')")' '<!(node -e "require(\'nan\')")'
], ],
'cflags': [ 'cflags': [
'<!(pkg-config --cflags vitastor)' '<!(pkg-config --cflags vitastor) -g'
], ],
'libraries': [ 'libraries': [
'<!(pkg-config --libs vitastor)', '<!(pkg-config --libs vitastor)',

View File

@ -34,13 +34,6 @@ public:
Nan::Persistent<v8::Function> callback; Nan::Persistent<v8::Function> callback;
}; };
static uint64_t get_ui64(const v8::Local<v8::Value> & val)
{
if (val->IsBigInt())
return val->ToBigInt(Nan::GetCurrentContext()).ToLocalChecked()->Uint64Value();
return Nan::To<int64_t>(val).FromJust();
}
////////////////////////////////////////////////// //////////////////////////////////////////////////
// NodeVitastor // NodeVitastor
////////////////////////////////////////////////// //////////////////////////////////////////////////
@ -109,14 +102,31 @@ void NodeVitastor::on_io_readable(uv_poll_t* handle, int status, int revents)
if (revents & UV_READABLE) if (revents & UV_READABLE)
{ {
NodeVitastor* self = (NodeVitastor*)handle->data; NodeVitastor* self = (NodeVitastor*)handle->data;
{
std::unique_lock<std::mutex> lock(self->mu);
vitastor_c_uring_handle_events(self->c); vitastor_c_uring_handle_events(self->c);
} }
self->run_postponed();
}
}
void NodeVitastor::run_postponed()
{
std::vector<std::function<void()>> callbacks;
{
std::unique_lock<std::mutex> lock(mu);
callbacks.swap(postponed);
}
for (auto & cb: callbacks)
{
cb();
}
} }
NodeVitastorRequest* NodeVitastor::get_read_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos) NodeVitastorRequest* NodeVitastor::get_read_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos)
{ {
uint64_t offset = get_ui64(info[argpos+0]); uint64_t offset = Nan::To<int64_t>(info[argpos+0]).FromJust();
uint64_t len = get_ui64(info[argpos+1]); uint64_t len = Nan::To<int64_t>(info[argpos+1]).FromJust();
uint8_t *buf = (uint8_t*)malloc(len); uint8_t *buf = (uint8_t*)malloc(len);
if (!buf) if (!buf)
{ {
@ -137,34 +147,34 @@ NodeVitastorRequest* NodeVitastor::get_read_request(const Nan::FunctionCallbackI
NAN_METHOD(NodeVitastor::Read) NAN_METHOD(NodeVitastor::Read)
{ {
TRACE("NodeVitastor::Read"); TRACE("NodeVitastor::Read");
if (info.Length() < 5)
Nan::ThrowError("Not enough arguments to read(pool, inode, offset, len, callback(err, buffer, version))");
NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This()); NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This());
uint64_t pool = get_ui64(info[0]); uint64_t pool = Nan::To<int64_t>(info[0]).FromJust();
uint64_t inode = get_ui64(info[1]); uint64_t inode = Nan::To<int64_t>(info[1]).FromJust();
auto req = self->get_read_request(info, 2); auto req = self->get_read_request(info, 2);
self->Ref(); self->Ref();
vitastor_c_read(self->c, ((pool << (64-POOL_ID_BITS)) | inode), req->offset, req->len, &req->iov, 1, on_read_finish, req); {
std::unique_lock<std::mutex> lock(self->mu);
vitastor_c_read(self->c, ((pool << (64-POOL_ID_BITS)) | inode), req->offset, req->len, &req->iov, 1, postpone_read_finish, req);
}
self->run_postponed();
} }
NodeVitastorRequest* NodeVitastor::get_write_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos) NodeVitastorRequest* NodeVitastor::get_write_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos)
{ {
uint64_t offset = get_ui64(info[argpos+0]); uint64_t offset = Nan::To<int64_t>(info[argpos+0]).FromJust();
const auto & bufarg = info[argpos+1]; const auto & bufarg = info[argpos+1];
uint64_t version = 0; uint64_t version = 0;
if (!info[argpos+2].IsEmpty() && if (!info[argpos+2].IsEmpty() && info[argpos+2]->IsObject())
!info[argpos+2]->IsFunction() &&
info[argpos+2]->IsObject())
{ {
auto key = Nan::New<v8::String>("version").ToLocalChecked(); auto key = Nan::New<v8::String>("version").ToLocalChecked();
auto params = info[argpos+2].As<v8::Object>(); auto params = info[argpos+2].As<v8::Object>();
auto versionObj = Nan::Get(params, key).ToLocalChecked(); auto versionObj = Nan::Get(params, key).ToLocalChecked();
if (!versionObj.IsEmpty()) if (!versionObj.IsEmpty())
version = get_ui64(versionObj); version = Nan::To<int64_t>(versionObj).FromJust();
argpos++; argpos++;
} }
@ -202,29 +212,29 @@ NodeVitastorRequest* NodeVitastor::get_write_request(const Nan::FunctionCallback
NAN_METHOD(NodeVitastor::Write) NAN_METHOD(NodeVitastor::Write)
{ {
TRACE("NodeVitastor::Write"); TRACE("NodeVitastor::Write");
if (info.Length() < 5)
Nan::ThrowError("Not enough arguments to write(pool, inode, offset, buf: Buffer | Buffer[], { version }?, callback(err))");
NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This()); NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This());
uint64_t pool = get_ui64(info[0]); uint64_t pool = Nan::To<int64_t>(info[0]).FromJust();
uint64_t inode = get_ui64(info[1]); uint64_t inode = Nan::To<int64_t>(info[1]).FromJust();
auto req = self->get_write_request(info, 2); auto req = self->get_write_request(info, 2);
self->Ref(); self->Ref();
{
std::unique_lock<std::mutex> lock(self->mu);
vitastor_c_write(self->c, ((pool << (64-POOL_ID_BITS)) | inode), req->offset, req->len, req->version, vitastor_c_write(self->c, ((pool << (64-POOL_ID_BITS)) | inode), req->offset, req->len, req->version,
req->iov_list.size() ? req->iov_list.data() : &req->iov, req->iov_list.size() ? req->iov_list.data() : &req->iov,
req->iov_list.size() ? req->iov_list.size() : 1, req->iov_list.size() ? req->iov_list.size() : 1,
on_write_finish, req); postpone_write_finish, req);
}
self->run_postponed();
} }
// sync(callback(err)) // sync(callback(err))
NAN_METHOD(NodeVitastor::Sync) NAN_METHOD(NodeVitastor::Sync)
{ {
TRACE("NodeVitastor::Sync"); TRACE("NodeVitastor::Sync");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to sync(callback(err))");
NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This()); NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This());
@ -232,28 +242,34 @@ NAN_METHOD(NodeVitastor::Sync)
auto req = new NodeVitastorRequest(self, callback); auto req = new NodeVitastorRequest(self, callback);
self->Ref(); self->Ref();
vitastor_c_sync(self->c, on_write_finish, req); {
std::unique_lock<std::mutex> lock(self->mu);
vitastor_c_sync(self->c, postpone_write_finish, req);
}
self->run_postponed();
} }
// read_bitmap(pool, inode, offset, len, with_parents, callback(err, bitmap_buffer)) // read_bitmap(pool, inode, offset, len, with_parents, callback(err, bitmap_buffer))
NAN_METHOD(NodeVitastor::ReadBitmap) NAN_METHOD(NodeVitastor::ReadBitmap)
{ {
TRACE("NodeVitastor::ReadBitmap"); TRACE("NodeVitastor::ReadBitmap");
if (info.Length() < 6)
Nan::ThrowError("Not enough arguments to read_bitmap(pool, inode, offset, len, with_parents, callback(err, bitmap_buffer))");
NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This()); NodeVitastor* self = Nan::ObjectWrap::Unwrap<NodeVitastor>(info.This());
uint64_t pool = get_ui64(info[0]); uint64_t pool = Nan::To<int64_t>(info[0]).FromJust();
uint64_t inode = get_ui64(info[1]); uint64_t inode = Nan::To<int64_t>(info[1]).FromJust();
uint64_t offset = get_ui64(info[2]); uint64_t offset = Nan::To<int64_t>(info[2]).FromJust();
uint64_t len = get_ui64(info[3]); uint64_t len = Nan::To<int64_t>(info[3]).FromJust();
bool with_parents = Nan::To<bool>(info[4]).FromJust(); bool with_parents = Nan::To<bool>(info[4]).FromJust();
v8::Local<v8::Function> callback = info[5].As<v8::Function>(); v8::Local<v8::Function> callback = info[5].As<v8::Function>();
auto req = new NodeVitastorRequest(self, callback); auto req = new NodeVitastorRequest(self, callback);
self->Ref(); self->Ref();
vitastor_c_read_bitmap(self->c, ((pool << (64-POOL_ID_BITS)) | inode), offset, len, with_parents, on_read_bitmap_finish, req); {
std::unique_lock<std::mutex> lock(self->mu);
vitastor_c_read_bitmap(self->c, ((pool << (64-POOL_ID_BITS)) | inode), offset, len, with_parents, postpone_read_bitmap_finish, req);
}
self->run_postponed();
} }
static void on_error(NodeVitastorRequest *req, Nan::Callback & nanCallback, long retval) static void on_error(NodeVitastorRequest *req, Nan::Callback & nanCallback, long retval)
@ -278,7 +294,7 @@ void NodeVitastor::on_read_finish(void *opaque, long retval, uint64_t version)
free(req->iov.iov_base); free(req->iov.iov_base);
nanCallback.Call(0, NULL, req); nanCallback.Call(0, NULL, req);
} }
else if (retval < 0 || (uint64_t)retval != req->len) else if (retval < 0)
{ {
free(req->iov.iov_base); free(req->iov.iov_base);
on_error(req, nanCallback, retval); on_error(req, nanCallback, retval);
@ -301,16 +317,7 @@ void NodeVitastor::on_write_finish(void *opaque, long retval)
Nan::HandleScope scope; Nan::HandleScope scope;
NodeVitastorRequest *req = (NodeVitastorRequest *)opaque; NodeVitastorRequest *req = (NodeVitastorRequest *)opaque;
Nan::Callback nanCallback(Nan::New(req->callback)); Nan::Callback nanCallback(Nan::New(req->callback));
if (retval < 0 || (uint64_t)retval != req->len)
{
on_error(req, nanCallback, retval); on_error(req, nanCallback, retval);
}
else
{
v8::Local<v8::Value> args[1];
args[0] = Nan::Null();
nanCallback.Call(1, args, req);
}
req->cli->Unref(); req->cli->Unref();
delete req; delete req;
} }
@ -336,6 +343,24 @@ void NodeVitastor::on_read_bitmap_finish(void *opaque, long retval, uint8_t *bit
delete req; delete req;
} }
void NodeVitastor::postpone_read_finish(void *opaque, long retval, uint64_t version)
{
NodeVitastorRequest *req = (NodeVitastorRequest *)opaque;
req->cli->postponed.push_back([=]() { on_read_finish(opaque, retval, version); });
}
void NodeVitastor::postpone_write_finish(void *opaque, long retval)
{
NodeVitastorRequest *req = (NodeVitastorRequest *)opaque;
req->cli->postponed.push_back([=]() { on_write_finish(opaque, retval); });
}
void NodeVitastor::postpone_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap)
{
NodeVitastorRequest *req = (NodeVitastorRequest *)opaque;
req->cli->postponed.push_back([=]() { on_read_bitmap_finish(opaque, retval, bitmap); });
}
//NAN_METHOD(NodeVitastor::Destroy) //NAN_METHOD(NodeVitastor::Destroy)
//{ //{
// TRACE("NodeVitastor::Destroy"); // TRACE("NodeVitastor::Destroy");
@ -348,8 +373,6 @@ void NodeVitastor::on_read_bitmap_finish(void *opaque, long retval, uint8_t *bit
NAN_METHOD(NodeVitastorImage::Create) NAN_METHOD(NodeVitastorImage::Create)
{ {
TRACE("NodeVitastorImage::Create"); TRACE("NodeVitastorImage::Create");
if (info.Length() < 2)
Nan::ThrowError("Not enough arguments to Image(client, name)");
v8::Local<v8::Object> parent = info[0].As<v8::Object>(); v8::Local<v8::Object> parent = info[0].As<v8::Object>();
std::string name = std::string(*Nan::Utf8String(info[1].As<v8::String>())); std::string name = std::string(*Nan::Utf8String(info[1].As<v8::String>()));
@ -363,6 +386,7 @@ NAN_METHOD(NodeVitastorImage::Create)
img->Ref(); img->Ref();
cli->Ref(); cli->Ref();
std::unique_lock<std::mutex> lock(cli->mu);
vitastor_c_watch_inode(cli->c, (char*)img->name.c_str(), on_watch_start, img); vitastor_c_watch_inode(cli->c, (char*)img->name.c_str(), on_watch_start, img);
info.GetReturnValue().Set(info.This()); info.GetReturnValue().Set(info.This());
@ -382,8 +406,6 @@ NodeVitastorImage::~NodeVitastorImage()
NAN_METHOD(NodeVitastorImage::Read) NAN_METHOD(NodeVitastorImage::Read)
{ {
TRACE("NodeVitastorImage::Read"); TRACE("NodeVitastorImage::Read");
if (info.Length() < 3)
Nan::ThrowError("Not enough arguments to read(offset, len, callback(err, buffer, version))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
@ -398,8 +420,6 @@ NAN_METHOD(NodeVitastorImage::Read)
NAN_METHOD(NodeVitastorImage::Write) NAN_METHOD(NodeVitastorImage::Write)
{ {
TRACE("NodeVitastorImage::Write"); TRACE("NodeVitastorImage::Write");
if (info.Length() < 3)
Nan::ThrowError("Not enough arguments to write(offset, buffer, { version }?, callback(err))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
@ -410,12 +430,9 @@ NAN_METHOD(NodeVitastorImage::Write)
img->exec_or_wait(req); img->exec_or_wait(req);
} }
// sync(callback(err))
NAN_METHOD(NodeVitastorImage::Sync) NAN_METHOD(NodeVitastorImage::Sync)
{ {
TRACE("NodeVitastorImage::Sync"); TRACE("NodeVitastorImage::Sync");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to sync(callback(err))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
@ -431,13 +448,11 @@ NAN_METHOD(NodeVitastorImage::Sync)
NAN_METHOD(NodeVitastorImage::ReadBitmap) NAN_METHOD(NodeVitastorImage::ReadBitmap)
{ {
TRACE("NodeVitastorImage::ReadBitmap"); TRACE("NodeVitastorImage::ReadBitmap");
if (info.Length() < 4)
Nan::ThrowError("Not enough arguments to read_bitmap(offset, len, with_parents, callback(err, bitmap_buffer))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
uint64_t offset = get_ui64(info[0]); uint64_t offset = Nan::To<int64_t>(info[0]).FromJust();
uint64_t len = get_ui64(info[1]); uint64_t len = Nan::To<int64_t>(info[1]).FromJust();
bool with_parents = Nan::To<bool>(info[2]).FromJust(); bool with_parents = Nan::To<bool>(info[2]).FromJust();
v8::Local<v8::Function> callback = info[3].As<v8::Function>(); v8::Local<v8::Function> callback = info[3].As<v8::Function>();
@ -451,12 +466,9 @@ NAN_METHOD(NodeVitastorImage::ReadBitmap)
img->exec_or_wait(req); img->exec_or_wait(req);
} }
// get_info(callback({ num, name, size, parent_id?, readonly?, meta?, mod_revision, block_size, bitmap_granularity, immediate_commit }))
NAN_METHOD(NodeVitastorImage::GetInfo) NAN_METHOD(NodeVitastorImage::GetInfo)
{ {
TRACE("NodeVitastorImage::GetInfo"); TRACE("NodeVitastorImage::GetInfo");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to get_info(callback({ num, name, size, parent_id?, readonly?, meta?, mod_revision, block_size, bitmap_granularity, immediate_commit }))");
NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This()); NodeVitastorImage* img = Nan::ObjectWrap::Unwrap<NodeVitastorImage>(info.This());
@ -485,41 +497,63 @@ void NodeVitastorImage::exec_request(NodeVitastorRequest *req)
{ {
if (req->op == NODE_VITASTOR_READ) if (req->op == NODE_VITASTOR_READ)
{ {
uint64_t ino = vitastor_c_inode_get_num(watch);
cli->Ref(); cli->Ref();
vitastor_c_read(cli->c, ino, req->offset, req->len, &req->iov, 1, NodeVitastor::on_read_finish, req); std::unique_lock<std::mutex> lock(cli->mu);
uint64_t ino = vitastor_c_inode_get_num(watch);
vitastor_c_read(cli->c, ino, req->offset, req->len, &req->iov, 1, NodeVitastor::postpone_read_finish, req);
} }
else if (req->op == NODE_VITASTOR_WRITE) else if (req->op == NODE_VITASTOR_WRITE)
{ {
uint64_t ino = vitastor_c_inode_get_num(watch);
cli->Ref(); cli->Ref();
std::unique_lock<std::mutex> lock(cli->mu);
uint64_t ino = vitastor_c_inode_get_num(watch);
vitastor_c_write(cli->c, ino, req->offset, req->len, req->version, vitastor_c_write(cli->c, ino, req->offset, req->len, req->version,
req->iov_list.size() ? req->iov_list.data() : &req->iov, req->iov_list.size() ? req->iov_list.data() : &req->iov,
req->iov_list.size() ? req->iov_list.size() : 1, req->iov_list.size() ? req->iov_list.size() : 1,
NodeVitastor::on_write_finish, req); NodeVitastor::postpone_write_finish, req);
} }
else if (req->op == NODE_VITASTOR_SYNC) else if (req->op == NODE_VITASTOR_SYNC)
{ {
cli->Ref();
std::unique_lock<std::mutex> lock(cli->mu);
uint64_t ino = vitastor_c_inode_get_num(watch); uint64_t ino = vitastor_c_inode_get_num(watch);
uint32_t imm = vitastor_c_inode_get_immediate_commit(cli->c, ino); uint32_t imm = vitastor_c_inode_get_immediate_commit(cli->c, ino);
cli->Ref();
if (imm != IMMEDIATE_ALL) if (imm != IMMEDIATE_ALL)
{ {
vitastor_c_sync(cli->c, NodeVitastor::on_write_finish, req); vitastor_c_sync(cli->c, NodeVitastor::postpone_write_finish, req);
} }
else else
{ {
NodeVitastor::on_write_finish(req, 0); NodeVitastor::postpone_write_finish(req, 0);
} }
} }
else if (req->op == NODE_VITASTOR_READ_BITMAP) else if (req->op == NODE_VITASTOR_READ_BITMAP)
{ {
uint64_t ino = vitastor_c_inode_get_num(watch);
cli->Ref(); cli->Ref();
vitastor_c_read_bitmap(cli->c, ino, req->offset, req->len, req->with_parents, NodeVitastor::on_read_bitmap_finish, req); std::unique_lock<std::mutex> lock(cli->mu);
uint64_t ino = vitastor_c_inode_get_num(watch);
vitastor_c_read_bitmap(cli->c, ino, req->offset, req->len, req->with_parents, NodeVitastor::postpone_read_bitmap_finish, req);
} }
else if (req->op == NODE_VITASTOR_GET_INFO) else if (req->op == NODE_VITASTOR_GET_INFO)
{ {
v8::Local<v8::Object> res = Nan::New<v8::Object>();
fill_info(res);
Nan::HandleScope scope;
Nan::Callback nanCallback(Nan::New(req->callback));
v8::Local<v8::Value> args[1];
args[0] = res;
nanCallback.Call(1, args, req);
delete req;
}
cli->run_postponed();
}
void NodeVitastorImage::fill_info(v8::Local<v8::Object> & res)
{
std::unique_lock<std::mutex> lock(cli->mu);
uint64_t size = vitastor_c_inode_get_size(watch); uint64_t size = vitastor_c_inode_get_size(watch);
uint64_t num = vitastor_c_inode_get_num(watch); uint64_t num = vitastor_c_inode_get_num(watch);
uint32_t block_size = vitastor_c_inode_get_block_size(cli->c, num); uint32_t block_size = vitastor_c_inode_get_block_size(cli->c, num);
@ -530,9 +564,6 @@ void NodeVitastorImage::exec_request(NodeVitastorRequest *req)
char *meta = vitastor_c_inode_get_meta(watch); char *meta = vitastor_c_inode_get_meta(watch);
uint64_t mod_revision = vitastor_c_inode_get_mod_revision(watch); uint64_t mod_revision = vitastor_c_inode_get_mod_revision(watch);
Nan::HandleScope scope;
v8::Local<v8::Object> res = Nan::New<v8::Object>();
Nan::Set(res, Nan::New<v8::String>("pool_id").ToLocalChecked(), Nan::New<v8::Number>(INODE_POOL(num))); Nan::Set(res, Nan::New<v8::String>("pool_id").ToLocalChecked(), Nan::New<v8::Number>(INODE_POOL(num)));
Nan::Set(res, Nan::New<v8::String>("inode_num").ToLocalChecked(), Nan::New<v8::Number>(INODE_NO_POOL(num))); Nan::Set(res, Nan::New<v8::String>("inode_num").ToLocalChecked(), Nan::New<v8::Number>(INODE_NO_POOL(num)));
if (size < ((uint64_t)1<<53)) if (size < ((uint64_t)1<<53))
@ -557,14 +588,6 @@ void NodeVitastorImage::exec_request(NodeVitastorRequest *req)
Nan::Set(res, Nan::New<v8::String>("block_size").ToLocalChecked(), Nan::New(block_size)); Nan::Set(res, Nan::New<v8::String>("block_size").ToLocalChecked(), Nan::New(block_size));
Nan::Set(res, Nan::New<v8::String>("bitmap_granularity").ToLocalChecked(), Nan::New(bitmap_granularity)); Nan::Set(res, Nan::New<v8::String>("bitmap_granularity").ToLocalChecked(), Nan::New(bitmap_granularity));
Nan::Set(res, Nan::New<v8::String>("immediate_commit").ToLocalChecked(), Nan::New(immediate_commit)); Nan::Set(res, Nan::New<v8::String>("immediate_commit").ToLocalChecked(), Nan::New(immediate_commit));
Nan::Callback nanCallback(Nan::New(req->callback));
v8::Local<v8::Value> args[1];
args[0] = res;
nanCallback.Call(1, args, req);
delete req;
}
} }
void NodeVitastorImage::on_watch_start(void *opaque, long retval) void NodeVitastorImage::on_watch_start(void *opaque, long retval)
@ -591,8 +614,6 @@ Nan::Persistent<v8::Function> NodeVitastorKV::listing_class;
NAN_METHOD(NodeVitastorKV::Create) NAN_METHOD(NodeVitastorKV::Create)
{ {
TRACE("NodeVitastorKV::Create"); TRACE("NodeVitastorKV::Create");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to new KV(client)");
v8::Local<v8::Object> parent = info[0].As<v8::Object>(); v8::Local<v8::Object> parent = info[0].As<v8::Object>();
NodeVitastor *cli = Nan::ObjectWrap::Unwrap<NodeVitastor>(parent); NodeVitastor *cli = Nan::ObjectWrap::Unwrap<NodeVitastor>(parent);
@ -600,6 +621,7 @@ NAN_METHOD(NodeVitastorKV::Create)
NodeVitastorKV *kv = new NodeVitastorKV(); NodeVitastorKV *kv = new NodeVitastorKV();
kv->cli = cli; kv->cli = cli;
{ {
std::unique_lock<std::mutex> lock(cli->mu);
kv->dbw = new vitastorkv_dbw_t((cluster_client_t*)vitastor_c_get_internal_client(cli->c)); kv->dbw = new vitastorkv_dbw_t((cluster_client_t*)vitastor_c_get_internal_client(cli->c));
} }
@ -618,12 +640,10 @@ NodeVitastorKV::~NodeVitastorKV()
NAN_METHOD(NodeVitastorKV::Open) NAN_METHOD(NodeVitastorKV::Open)
{ {
TRACE("NodeVitastorKV::Open"); TRACE("NodeVitastorKV::Open");
if (info.Length() < 4)
Nan::ThrowError("Not enough arguments to open(pool_id, inode_num, { ...config }, callback(err))");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
uint64_t inode_id = INODE_WITH_POOL(get_ui64(info[0]), get_ui64(info[1])); uint64_t inode_id = INODE_WITH_POOL(Nan::To<int64_t>(info[0]).FromJust(), Nan::To<int64_t>(info[1]).FromJust());
v8::Local<v8::Object> jsParams = info[2].As<v8::Object>(); v8::Local<v8::Object> jsParams = info[2].As<v8::Object>();
v8::Local<v8::Array> keys = Nan::GetOwnPropertyNames(jsParams).ToLocalChecked(); v8::Local<v8::Array> keys = Nan::GetOwnPropertyNames(jsParams).ToLocalChecked();
@ -654,8 +674,6 @@ NAN_METHOD(NodeVitastorKV::Open)
NAN_METHOD(NodeVitastorKV::Close) NAN_METHOD(NodeVitastorKV::Close)
{ {
TRACE("NodeVitastorKV::Close"); TRACE("NodeVitastorKV::Close");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to close(callback(err))");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
@ -677,8 +695,6 @@ NAN_METHOD(NodeVitastorKV::Close)
NAN_METHOD(NodeVitastorKV::SetConfig) NAN_METHOD(NodeVitastorKV::SetConfig)
{ {
TRACE("NodeVitastorKV::SetConfig"); TRACE("NodeVitastorKV::SetConfig");
if (info.Length() < 1)
Nan::ThrowError("Not enough arguments to set_config({ ...config })");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
@ -735,8 +751,6 @@ void NodeVitastorKV::get_impl(const Nan::FunctionCallbackInfo<v8::Value> & info,
NAN_METHOD(NodeVitastorKV::Get) NAN_METHOD(NodeVitastorKV::Get)
{ {
TRACE("NodeVitastorKV::Get"); TRACE("NodeVitastorKV::Get");
if (info.Length() < 2)
Nan::ThrowError("Not enough arguments to get(key, callback(err, value))");
get_impl(info, false); get_impl(info, false);
} }
@ -744,8 +758,6 @@ NAN_METHOD(NodeVitastorKV::Get)
NAN_METHOD(NodeVitastorKV::GetCached) NAN_METHOD(NodeVitastorKV::GetCached)
{ {
TRACE("NodeVitastorKV::GetCached"); TRACE("NodeVitastorKV::GetCached");
if (info.Length() < 2)
Nan::ThrowError("Not enough arguments to get_cached(key, callback(err, value))");
get_impl(info, true); get_impl(info, true);
} }
@ -764,12 +776,10 @@ static std::function<bool(int, const std::string &)> make_cas_callback(NodeVitas
}; };
} }
// set(key, value, callback(err), cas_compare(old_value)?) // set(key, value, callback(err), cas_compare(old_value))
NAN_METHOD(NodeVitastorKV::Set) NAN_METHOD(NodeVitastorKV::Set)
{ {
TRACE("NodeVitastorKV::Set"); TRACE("NodeVitastorKV::Set");
if (info.Length() < 3)
Nan::ThrowError("Not enough arguments to set(key, value, callback(err), cas_compare(old_value)?)");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
@ -803,12 +813,10 @@ NAN_METHOD(NodeVitastorKV::Set)
}, cas_cb); }, cas_cb);
} }
// del(key, callback(err), cas_compare(old_value)?) // del(key, callback(err), cas_compare(old_value))
NAN_METHOD(NodeVitastorKV::Del) NAN_METHOD(NodeVitastorKV::Del)
{ {
TRACE("NodeVitastorKV::Del"); TRACE("NodeVitastorKV::Del");
if (info.Length() < 2)
Nan::ThrowError("Not enough arguments to del(key, callback(err), cas_compare(old_value)?)");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
@ -862,6 +870,7 @@ NAN_METHOD(NodeVitastorKV::List)
{ {
TRACE("NodeVitastorKV::Destroy"); TRACE("NodeVitastorKV::Destroy");
NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This()); NodeVitastorKV* kv = Nan::ObjectWrap::Unwrap<NodeVitastorKV>(info.This());
std::unique_lock<std::mutex> lock(self->mu);
if (!kv->dead) if (!kv->dead)
kv->Unref(); kv->Unref();
}*/ }*/
@ -887,7 +896,10 @@ NAN_METHOD(NodeVitastorKVListing::Create)
NodeVitastorKVListing *list = new NodeVitastorKVListing(); NodeVitastorKVListing *list = new NodeVitastorKVListing();
list->kv = kv; list->kv = kv;
{
std::unique_lock<std::mutex> lock(kv->cli->mu);
list->handle = list->kv->dbw->list_start(start_key); list->handle = list->kv->dbw->list_start(start_key);
}
list->Wrap(info.This()); list->Wrap(info.This());
kv->Ref(); kv->Ref();
@ -898,54 +910,36 @@ NodeVitastorKVListing::~NodeVitastorKVListing()
{ {
if (handle) if (handle)
{ {
std::unique_lock<std::mutex> lock(kv->cli->mu);
kv->dbw->list_close(handle); kv->dbw->list_close(handle);
handle = NULL; handle = NULL;
} }
if (iter)
{
delete iter;
iter = NULL;
}
kv->Unref(); kv->Unref();
} }
// next(callback(err, value)?) // next(callback(err, value))
NAN_METHOD(NodeVitastorKVListing::Next) NAN_METHOD(NodeVitastorKVListing::Next)
{ {
TRACE("NodeVitastorKVListing::Next"); TRACE("NodeVitastorKVListing::Next");
NodeVitastorKVListing* list = Nan::ObjectWrap::Unwrap<NodeVitastorKVListing>(info.This()); NodeVitastorKVListing* list = Nan::ObjectWrap::Unwrap<NodeVitastorKVListing>(info.This());
if (info.Length() > 0)
{
v8::Local<v8::Function> callback = info[0].As<v8::Function>(); v8::Local<v8::Function> callback = info[0].As<v8::Function>();
if (list->iter) auto req = new NodeVitastorRequest(list->kv->cli, callback);
{
delete list->iter;
}
list->iter = new NodeVitastorRequest(list->kv->cli, callback);
}
if (!list->handle) if (!list->handle)
{ {
// Already closed // Already closed
if (list->iter)
{
auto req = list->iter;
list->iter = NULL;
Nan::Callback nanCallback(Nan::New(req->callback)); Nan::Callback nanCallback(Nan::New(req->callback));
v8::Local<v8::Value> args[1]; v8::Local<v8::Value> args[1];
args[0] = Nan::New<v8::Int32>(-EINVAL); args[0] = Nan::New<v8::Int32>(-EINVAL);
nanCallback.Call(1, args, req); nanCallback.Call(1, args, req);
delete req; delete req;
}
return; return;
} }
list->kv->Ref(); list->kv->Ref();
list->kv->dbw->list_next(list->handle, [list](int res, const std::string & key, const std::string & value) list->kv->dbw->list_next(list->handle, [list, req](int res, const std::string & key, const std::string & value)
{ {
auto req = list->iter;
list->iter = NULL;
Nan::HandleScope scope; Nan::HandleScope scope;
Nan::Callback nanCallback(Nan::New(req->callback)); Nan::Callback nanCallback(Nan::New(req->callback));
v8::Local<v8::Value> args[3]; v8::Local<v8::Value> args[3];
@ -953,10 +947,7 @@ NAN_METHOD(NodeVitastorKVListing::Next)
args[1] = !res ? v8::Local<v8::Value>(Nan::New<v8::String>(key).ToLocalChecked()) : v8::Local<v8::Value>(Nan::Null()); args[1] = !res ? v8::Local<v8::Value>(Nan::New<v8::String>(key).ToLocalChecked()) : v8::Local<v8::Value>(Nan::Null());
args[2] = !res ? v8::Local<v8::Value>(Nan::New<v8::String>(value).ToLocalChecked()) : v8::Local<v8::Value>(Nan::Null()); args[2] = !res ? v8::Local<v8::Value>(Nan::New<v8::String>(value).ToLocalChecked()) : v8::Local<v8::Value>(Nan::Null());
nanCallback.Call(3, args, req); nanCallback.Call(3, args, req);
if (list->iter)
delete req; delete req;
else
list->iter = req;
list->kv->Unref(); list->kv->Unref();
}); });
} }
@ -970,12 +961,8 @@ NAN_METHOD(NodeVitastorKVListing::Close)
if (list->handle) if (list->handle)
{ {
std::unique_lock<std::mutex> lock(list->kv->cli->mu);
list->kv->dbw->list_close(list->handle); list->kv->dbw->list_close(list->handle);
list->handle = NULL; list->handle = NULL;
} }
if (list->iter)
{
delete list->iter;
list->iter = NULL;
}
} }

View File

@ -4,6 +4,8 @@
#ifndef NODE_VITASTOR_CLIENT_H #ifndef NODE_VITASTOR_CLIENT_H
#define NODE_VITASTOR_CLIENT_H #define NODE_VITASTOR_CLIENT_H
#include <mutex>
#include <nan.h> #include <nan.h>
#include <vitastor_c.h> #include <vitastor_c.h>
#include <vitastor_kv.h> #include <vitastor_kv.h>
@ -32,6 +34,9 @@ private:
vitastor_c *c = NULL; vitastor_c *c = NULL;
int eventfd = -1; int eventfd = -1;
uv_poll_t poll_watcher; uv_poll_t poll_watcher;
// FIXME: Is it really needed?
std::mutex mu;
std::vector<std::function<void()>> postponed;
NodeVitastor(); NodeVitastor();
@ -40,6 +45,11 @@ private:
static void on_write_finish(void *opaque, long retval); static void on_write_finish(void *opaque, long retval);
static void on_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap); static void on_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap);
void run_postponed();
static void postpone_read_finish(void *opaque, long retval, uint64_t version);
static void postpone_write_finish(void *opaque, long retval);
static void postpone_read_bitmap_finish(void *opaque, long retval, uint8_t *bitmap);
NodeVitastorRequest* get_read_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos); NodeVitastorRequest* get_read_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos);
NodeVitastorRequest* get_write_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos); NodeVitastorRequest* get_write_request(const Nan::FunctionCallbackInfo<v8::Value> & info, int argpos);
@ -76,6 +86,7 @@ private:
static void on_watch_start(void *opaque, long retval); static void on_watch_start(void *opaque, long retval);
void exec_request(NodeVitastorRequest *req); void exec_request(NodeVitastorRequest *req);
void exec_or_wait(NodeVitastorRequest *req); void exec_or_wait(NodeVitastorRequest *req);
void fill_info(v8::Local<v8::Object> & res);
}; };
class NodeVitastorKV: public Nan::ObjectWrap class NodeVitastorKV: public Nan::ObjectWrap
@ -95,9 +106,9 @@ public:
static NAN_METHOD(Get); static NAN_METHOD(Get);
// get_cached(key, callback(err, value)) // get_cached(key, callback(err, value))
static NAN_METHOD(GetCached); static NAN_METHOD(GetCached);
// set(key, value, callback(err), cas_compare(old_value)?) // set(key, value, callback(err), cas_compare(old_value))
static NAN_METHOD(Set); static NAN_METHOD(Set);
// del(key, callback(err), cas_compare(old_value)?) // del(key, callback(err), cas_compare(old_value))
static NAN_METHOD(Del); static NAN_METHOD(Del);
// list(start_key?) // list(start_key?)
static NAN_METHOD(List); static NAN_METHOD(List);
@ -120,7 +131,7 @@ class NodeVitastorKVListing: public Nan::ObjectWrap
public: public:
// constructor(node_vitastor_kv, start_key?) // constructor(node_vitastor_kv, start_key?)
static NAN_METHOD(Create); static NAN_METHOD(Create);
// next(callback(err, value)?) // next(callback(err, value))
static NAN_METHOD(Next); static NAN_METHOD(Next);
// close() // close()
static NAN_METHOD(Close); static NAN_METHOD(Close);
@ -130,7 +141,6 @@ public:
private: private:
NodeVitastorKV *kv = NULL; NodeVitastorKV *kv = NULL;
void *handle = NULL; void *handle = NULL;
NodeVitastorRequest *iter = NULL;
}; };
#endif #endif

View File

@ -1 +0,0 @@
See [../docs/installation/opennebula.en.md](../docs/installation/opennebula.en.md).

View File

@ -1,36 +0,0 @@
#!/bin/bash
set -e
reapply_patch() {
if ! [[ -e $1 ]]; then
echo "$1 does not exist, OpenNebula is not installed"
elif ! patch -f --dry-run -F 0 -R $1 < $2 >/dev/null; then
already_applied=0
if ! patch --no-backup-if-mismatch -r - -F 0 -f $1 < $2; then
applied_ok=0
echo "ERROR: Failed to patch file $1, please apply the patch $2 manually"
fi
fi
}
echo "Reapplying Vitastor patches to OpenNebula's oned.conf, vmm_execrc and downloader.sh"
already_applied=1
applied_ok=1
reapply_patch /var/lib/one/remotes/datastore/downloader.sh /var/lib/one/remotes/datastore/vitastor/downloader-vitastor.sh.diff
reapply_patch /etc/one/vmm_exec/vmm_execrc /var/lib/one/remotes/datastore/vitastor/vmm_execrc.diff
if [[ -e /etc/one/oned.conf ]]; then
if ! /var/lib/one/remotes/datastore/vitastor/patch-oned-conf.py /etc/one/oned.conf; then
applied_ok=0
already_applied=0
fi
fi
if [[ "$already_applied" = 1 ]]; then
echo "OK: Vitastor OpenNebula patches are already applied"
elif [[ "$applied_ok" = 1 ]]; then
echo "OK: Vitastor OpenNebula patches successfully applied"
fi
if [[ -f /etc/apparmor.d/local/abstractions/libvirt-qemu ]]; then
if ! grep -q /etc/vitastor/vitastor.conf /etc/apparmor.d/local/abstractions/libvirt-qemu; then
echo ' "/etc/vitastor/vitastor.conf" r,' >> /etc/apparmor.d/local/abstractions/libvirt-qemu
fi
fi

View File

@ -1,76 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# This script is used to copy a VM image (SRC) to the image repository as DST
# -------- Set up the environment to source common tools & conf ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh
# -------- Get cp and datastore arguments from OpenNebula core ------------
DRV_ACTION=`cat -`
ID=$1
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
unset i XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/POOL_NAME \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/IMAGE_PREFIX \
/DS_DRIVER_ACTION_DATA/IMAGE/PATH \
/DS_DRIVER_ACTION_DATA/IMAGE/SIZE \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF)
unset i
BASE_PATH="${XPATH_ELEMENTS[i++]}"
BRIDGE_LIST="${XPATH_ELEMENTS[i++]}"
POOL_NAME="${XPATH_ELEMENTS[i++]}"
IMAGE_PREFIX="${XPATH_ELEMENTS[i++]:-one}"
SRC="${XPATH_ELEMENTS[i++]}"
SIZE="${XPATH_ELEMENTS[i++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[i++]}"
DST_HOST=`get_destination_host $ID`
if [ -z "$DST_HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
if [ -n "$POOL_NAME" ]; then
CLI="$CLI --pool ${POOL_NAME}"
fi
SAFE_DIRS=""
DST="${IMAGE_PREFIX}-${ID}"
ssh_exec_and_log "$DST_HOST" "$CLI create --parent $SRC $DST" \
"Error during $CLI create --parent $SRC $DST in $DST_HOST"
ssh_exec_and_log "$DST_HOST" "$CLI flatten $DST" \
"Error during $CLI create flatten $DST in $DST_HOST"
echo "$DST raw"

View File

@ -1,135 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# This script is used to copy a local image SRC to the image repository as DST
# -------- Set up the environment to source common tools & conf ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh
# -------- Get cp and datastore arguments from OpenNebula core ------------
DRV_ACTION=`cat -`
ID=$1
export DRV_ACTION
UTILS_PATH="${DRIVER_PATH}/.."
XPATH="$UTILS_PATH/xpath.rb -b $DRV_ACTION"
unset i XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/RESTRICTED_DIRS \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/SAFE_DIRS \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/POOL_NAME \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/IMAGE_PREFIX \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/STAGING_DIR \
/DS_DRIVER_ACTION_DATA/IMAGE/PATH \
/DS_DRIVER_ACTION_DATA/IMAGE/SIZE \
/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5 \
/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/SHA1 \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/NO_DECOMPRESS \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/LIMIT_TRANSFER_BW \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF)
unset i
BASE_PATH="${XPATH_ELEMENTS[i++]}"
RESTRICTED_DIRS="${XPATH_ELEMENTS[i++]}"
SAFE_DIRS="${XPATH_ELEMENTS[i++]}"
BRIDGE_LIST="${XPATH_ELEMENTS[i++]}"
POOL_NAME="${XPATH_ELEMENTS[i++]}"
IMAGE_PREFIX="${XPATH_ELEMENTS[i++]:-one}"
STAGING_DIR="${XPATH_ELEMENTS[i++]:-/var/tmp}"
SRC="${XPATH_ELEMENTS[i++]}"
SIZE="${XPATH_ELEMENTS[i++]}"
MD5="${XPATH_ELEMENTS[i++]}"
SHA1="${XPATH_ELEMENTS[i++]}"
NO_DECOMPRESS="${XPATH_ELEMENTS[i++]}"
LIMIT_TRANSFER_BW="${XPATH_ELEMENTS[i++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[i++]}"
DST_HOST=`get_destination_host $ID`
if [ -z "$DST_HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi
CLI=vitastor-cli
QEMU_ARG=""
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
QEMU_ARG=":config_path=${VITASTOR_CONF}"
fi
if [ -n "$POOL_NAME" ]; then
CLI="$CLI --pool ${POOL_NAME}"
fi
set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS"
IMAGE_HASH=`generate_image_hash`
TMP_DST="$STAGING_DIR/$IMAGE_HASH"
DST="${IMAGE_PREFIX}-${ID}"
DOWNLOADER_ARGS=`set_downloader_args "$MD5" "$SHA1" "$NO_DECOMPRESS" "$LIMIT_TRANSFER_BW" "$SRC" -`
COPY_COMMAND="$UTILS_PATH/downloader.sh $DOWNLOADER_ARGS"
case $SRC in
http://*|https://*)
log "Downloading $SRC to the image repository"
DUMP="$COPY_COMMAND"
;;
*)
if [ `check_restricted $SRC` -eq 1 ]; then
log_error "Not allowed to copy images from $RESTRICTED_DIRS"
error_message "Not allowed to copy image file $SRC"
exit -1
fi
log "Copying local image $SRC to the image repository"
DUMP="$COPY_COMMAND"
;;
esac
multiline_exec_and_log "set -e -o pipefail; $DUMP | $SSH $DST_HOST $DD of=$TMP_DST bs=1M" \
"Error copying $SRC to $DST_HOST:$TMP_DST"
REGISTER_CMD=$(cat <<EOF
set -e -o pipefail
SIZE=\$($QEMU_IMG info --output json "$TMP_DST" | jq -r '.["virtual-size"]')
$CLI create -s \$SIZE "$DST"
$QEMU_IMG convert -O raw "$TMP_DST" "vitastor:image=$DST$QEMU_ARG"
# remove original
$RM -f $TMP_DST
EOF
)
ssh_exec_and_log "$DST_HOST" "$REGISTER_CMD" "Error registering $DST in $DST_HOST"
echo "$DST raw"

View File

@ -1,555 +0,0 @@
#!/bin/bash
# -------------------------------------------------------------------------- #
# Copyright 2002-2023, OpenNebula Project, OpenNebula Systems #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
VAR_LOCATION=/var/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
VAR_LOCATION=$ONE_LOCATION/var
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
# Escape single quotes
function esc_sq
{
echo "$1" | sed -e "s/'/'\\\''/g"
}
# Execute a command (first parameter) and use the first kb of stdout
# to determine the file type
function get_type
{
if [ "$NO_DECOMPRESS" = "yes" ]; then
echo "application/octet-stream"
else
command=$1
( eval "$command" | head -n 1024 | file -b --mime-type - ) 2>/dev/null
fi
}
# Gets the command needed to decompress an stream.
function get_decompressor
{
type=$1
case "$type" in
"application/x-gzip"|"application/gzip")
echo "gunzip -c -"
;;
"application/x-bzip2")
echo "bunzip2 -qc -"
;;
"application/x-xz")
echo "unxz -c -"
;;
*)
echo "cat"
;;
esac
}
# Function called to decompress a stream. The first parameter is the command
# used to decompress the stream. Second parameter is the output file or
# - for stdout.
function decompress
{
command="$1"
to="$2"
if [ "$to" = "-" ]; then
$command
else
$command > "$to"
fi
}
# Function called to hash a stream. First parameter is the algorithm name.
function hasher
{
if [ -n "$1" ]; then
openssl dgst -$1 | awk '{print $NF}' > $HASH_FILE
else
# Needs something consuming stdin or the pipe will break
cat >/dev/null
fi
}
# Unarchives a tar or a zip a file to a directory with the same name.
function unarchive
{
TO="$1"
file_type=$(get_type "cat $TO")
tmp="$TO"
# Add full path if it is relative
if [ ${tmp:0:1} != "/" ]; then
tmp="$PWD/$tmp"
fi
IN="$tmp.tmp"
OUT="$tmp"
case "$file_type" in
"application/x-tar")
command="tar -xf $IN -C $OUT"
;;
"application/zip")
command="unzip -d $OUT $IN"
;;
*)
command=""
;;
esac
if [ -n "$command" ]; then
mv "$OUT" "$IN"
mkdir "$OUT"
$command
if [ "$?" != "0" ]; then
echo "Error uncompressing archive" >&2
exit -1
fi
rm "$IN"
fi
}
function s3_env
{
XPATH="$DRIVER_PATH/xpath.rb -b $DRV_ACTION"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH /DS_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/ACCESS_KEY_ID \
/DS_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/SECRET_ACCESS_KEY \
/DS_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/REGION \
/DS_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/AWS \
/DS_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/ENDPOINT)
S3_ACCESS_KEY_ID="${XPATH_ELEMENTS[j++]}"
S3_SECRET_ACCESS_KEY="${XPATH_ELEMENTS[j++]}"
S3_REGION="${XPATH_ELEMENTS[j++]}"
S3_AWS="${XPATH_ELEMENTS[j++]}"
S3_ENDPOINT="${XPATH_ELEMENTS[j++]}"
CURRENT_DATE_DAY="$(date -u '+%Y%m%d')"
CURRENT_DATE_ISO8601="${CURRENT_DATE_DAY}T$(date -u '+%H%M%S')Z"
}
# Create an SHA-256 hash in hexadecimal.
# Usage:
# hash_sha256 <string>
function hash_sha256 {
printf "${1}" | openssl dgst -sha256 | sed 's/^.* //'
}
# Create an SHA-256 hmac in hexadecimal.
# Usage:
# hmac_sha256 <key> <data>
function hmac_sha256 {
printf "${2}" | openssl dgst -sha256 -mac HMAC -macopt "${1}" | sed 's/^.* //'
}
# Create the signature.
# Usage:
# create_signature
function create_signature {
stringToSign="AWS4-HMAC-SHA256\n${CURRENT_DATE_ISO8601}\n${CURRENT_DATE_DAY}/${S3_REGION}/s3/aws4_request\n$(hash_sha256 "${HTTP_CANONICAL_REQUEST}")"
dateKey=$(hmac_sha256 key:"AWS4${S3_SECRET_ACCESS_KEY}" "${CURRENT_DATE_DAY}")
regionKey=$(hmac_sha256 hexkey:"${dateKey}" "${S3_REGION}")
serviceKey=$(hmac_sha256 hexkey:"${regionKey}" "s3")
signingKey=$(hmac_sha256 hexkey:"${serviceKey}" "aws4_request")
printf "${stringToSign}" | openssl dgst -sha256 -mac HMAC -macopt hexkey:"${signingKey}" | sed 's/.*(stdin)= //'
}
function s3_curl_args
{
FROM="$1"
ENDPOINT="$S3_ENDPOINT"
OBJECT=$(basename "$FROM")
BUCKET=$(basename $(dirname "$FROM"))
DATE="`date -u +'%a, %d %b %Y %H:%M:%S GMT'`"
AUTH_STRING="GET\n\n\n${DATE}\n/${BUCKET}/${OBJECT}"
SIGNED_AUTH_STRING=`echo -en "$AUTH_STRING" | \
openssl sha1 -hmac ${S3_SECRET_ACCESS_KEY} -binary | \
base64`
echo " -H \"Date: ${DATE}\"" \
" -H \"Authorization: AWS ${S3_ACCESS_KEY_ID}:${SIGNED_AUTH_STRING}\"" \
" '$(esc_sq "${ENDPOINT}/${BUCKET}/${OBJECT}")'"
}
function s3_curl_args_aws
{
FROM="$1"
OBJECT=$(basename "$FROM")
BUCKET=$(basename "$(dirname "$FROM")")
ENDPOINT="$BUCKET.s3.amazonaws.com"
AWS_S3_PATH="$(echo $OBJECT | sed 's;^\([^/]\);/\1;')"
HTTP_REQUEST_PAYLOAD_HASH="$(echo "" | openssl dgst -sha256 | sed 's/^.* //')"
HTTP_CANONICAL_REQUEST_URI="${AWS_S3_PATH}"
HTTP_REQUEST_CONTENT_TYPE='application/octet-stream'
HTTP_CANONICAL_REQUEST_HEADERS="content-type:${HTTP_REQUEST_CONTENT_TYPE}
host:${ENDPOINT}
x-amz-content-sha256:${HTTP_REQUEST_PAYLOAD_HASH}
x-amz-date:${CURRENT_DATE_ISO8601}"
HTTP_REQUEST_SIGNED_HEADERS="content-type;host;x-amz-content-sha256;x-amz-date"
HTTP_CANONICAL_REQUEST="GET
${HTTP_CANONICAL_REQUEST_URI}\n
${HTTP_CANONICAL_REQUEST_HEADERS}\n
${HTTP_REQUEST_SIGNED_HEADERS}
${HTTP_REQUEST_PAYLOAD_HASH}"
SIGNATURE="$(create_signature)"
HTTP_REQUEST_AUTHORIZATION_HEADER="AWS4-HMAC-SHA256 Credential=${S3_ACCESS_KEY_ID}/${CURRENT_DATE_DAY}/${S3_REGION}/s3/aws4_request, SignedHeaders=${HTTP_REQUEST_SIGNED_HEADERS}, Signature=${SIGNATURE}"
echo " -H \"Authorization: ${HTTP_REQUEST_AUTHORIZATION_HEADER}\"" \
" -H \"content-type: ${HTTP_REQUEST_CONTENT_TYPE}\"" \
" -H \"x-amz-content-sha256: ${HTTP_REQUEST_PAYLOAD_HASH}\"" \
" -H \"x-amz-date: ${CURRENT_DATE_ISO8601}\"" \
" \"https://${ENDPOINT}${HTTP_CANONICAL_REQUEST_URI}\""
}
function get_rbd_cmd
{
local i j URL_ELEMENTS
FROM="$1"
URL_RB="$DRIVER_PATH/url.rb"
while IFS= read -r -d '' element; do
URL_ELEMENTS[i++]="$element"
done < <($URL_RB "$FROM" \
USER \
HOST \
SOURCE \
PARAM_DS \
PARAM_CEPH_USER \
PARAM_CEPH_KEY \
PARAM_CEPH_CONF)
USER="${URL_ELEMENTS[j++]}"
DST_HOST="${URL_ELEMENTS[j++]}"
SOURCE="${URL_ELEMENTS[j++]}"
DS="${URL_ELEMENTS[j++]}"
CEPH_USER="${URL_ELEMENTS[j++]}"
CEPH_KEY="${URL_ELEMENTS[j++]}"
CEPH_CONF="${URL_ELEMENTS[j++]}"
# Remove leading '/'
SOURCE="${SOURCE#/}"
if [ -n "$USER" ]; then
DST_HOST="$USER@$DST_HOST"
fi
if [ -n "$CEPH_USER" ]; then
RBD="$RBD --id '$(esc_sq "${CEPH_USER}")'"
fi
if [ -n "$CEPH_KEY" ]; then
RBD="$RBD --keyfile '$(esc_sq "${CEPH_KEY}")'"
fi
if [ -n "$CEPH_CONF" ]; then
RBD="$RBD --conf '$(esc_sq "${CEPH_CONF}")'"
fi
echo "ssh '$(esc_sq "$DST_HOST")' \"$RBD export '$(esc_sq "$SOURCE")' -\""
}
function get_vitastor_cmd
{
local i j URL_ELEMENTS
FROM="$1"
URL_RB="$DRIVER_PATH/url.rb"
while IFS= read -r -d '' element; do
URL_ELEMENTS[i++]="$element"
done < <($URL_RB "$FROM" \
USER \
HOST \
SOURCE \
PARAM_DS \
PARAM_VITASTOR_CONF)
USER="${URL_ELEMENTS[j++]}"
DST_HOST="${URL_ELEMENTS[j++]}"
SOURCE="${URL_ELEMENTS[j++]}"
DS="${URL_ELEMENTS[j++]}"
VITASTOR_CONF="${URL_ELEMENTS[j++]}"
# Remove leading '/'
SOURCE="${SOURCE#/}"
if [ -n "$USER" ]; then
DST_HOST="$USER@$DST_HOST"
fi
local CLI
CLI="vitastor-cli"
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path '$(esc_sq "${VITASTOR_CONF}")'"
fi
echo "ssh '$(esc_sq "$DST_HOST")' \"$CLI dd iimg='$(esc_sq "$SOURCE")'\""
}
# Compare 2 version strings using sort -V
# Usage:
# verlte "3.2.9" "3.4.0"
function verlte() {
[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
}
# Returns curl retry options based on its version
function curl_retry_args {
[ "$NO_RETRY" = "yes" ] && return
RETRY_ARGS="--retry 3 --retry-delay 3"
CURL_VER=`curl --version | grep -o 'curl [0-9\.]*' | awk '{print $2}'`
# To retry also on conn-reset-by-peer fresh curl is needed
if verlte "7.71.0" "$CURL_VER" && [ -z ${MAX_SIZE} ] ; then
RETRY_ARGS+=" --retry-all-errors"
fi
echo $RETRY_ARGS
}
TEMP=`getopt -o m:s:l:c:no -l md5:,sha1:,limit:,max-size:,nodecomp,noretry -- "$@"`
if [ $? != 0 ] ; then
echo "Arguments error" >&2
exit -1
fi
eval set -- "$TEMP"
while true; do
case "$1" in
-m|--md5)
HASH_TYPE=md5
HASH=$2
shift 2
;;
-s|--sha1)
HASH_TYPE=sha1
HASH=$2
shift 2
;;
-n|--nodecomp)
export NO_DECOMPRESS="yes"
shift
;;
-l|--limit)
export LIMIT_RATE="$2"
shift 2
;;
-c|--max-size)
export MAX_SIZE="$2"
shift 2
;;
-o|--noretry)
export NO_RETRY="yes"
shift
;;
--)
shift
break
;;
*)
shift
;;
esac
done
FROM="$1"
TO="$2"
if [ -n "${HASH_TYPE}" -a -n "${MAX_SIZE}" ]; then
echo "Hash check not supported for partial downloads" >&2
exit -1
else
# File used by the hasher function to store the resulting hash
export HASH_FILE="/tmp/downloader.hash.$$"
fi
GLOBAL_CURL_ARGS="--fail -sS -k -L $(curl_retry_args)"
case "$FROM" in
http://*|https://*)
# -k so it does not check the certificate
# -L to follow redirects
# -sS to hide output except on failure
# --limit_rate to limit the bw
curl_args="$GLOBAL_CURL_ARGS '$(esc_sq "${FROM}")'"
if [ -n "$LIMIT_RATE" ]; then
curl_args="--limit-rate $LIMIT_RATE $curl_args"
fi
command="curl $curl_args"
;;
ssh://*)
# pseudo-url for ssh transfers ssh://user@host:path
# -l to limit the bw
ssh_src=${FROM#ssh://}
ssh_arg=(${ssh_src/:/ })
rmt_cmd="\"cat '$(esc_sq "${ssh_arg[1]}")'\""
command="ssh ${ssh_arg[0]} $rmt_cmd"
;;
s3://*)
# Read s3 environment
s3_env
if [ -z "$S3_ACCESS_KEY_ID" -o -z "$S3_SECRET_ACCESS_KEY" ]; then
echo "S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY are required" >&2
exit -1
fi
curl_args=""
if [[ "$S3_AWS" =~ (no|NO) ]]; then
curl_args="$(s3_curl_args "$FROM")"
else
curl_args="$(s3_curl_args_aws "$FROM")"
fi
command="curl $GLOBAL_CURL_ARGS $curl_args"
;;
rbd://*)
command="$(get_rbd_cmd "$FROM")"
;;
vitastor://*)
command="$(get_vitastor_cmd "$FROM")"
;;
vcenter://*)
command="$VAR_LOCATION/remotes/datastore/vcenter_downloader.rb '$(esc_sq "$FROM")'"
;;
lxd://*)
file_type="application/octet-stream"
command="$VAR_LOCATION/remotes/datastore/lxd_downloader.sh \"$FROM\""
;;
restic://*)
eval `$VAR_LOCATION/remotes/datastore/restic_downloader.rb "$FROM" | grep -e '^command=' -e '^clean_command='`
;;
rsync://*)
eval `$VAR_LOCATION/remotes/datastore/rsync_downloader.rb "$FROM" | grep -e '^command=' -e '^clean_command='`
;;
*)
if [ ! -r $FROM ]; then
echo "Cannot read from $FROM" >&2
exit -1
fi
command="cat '$(esc_sq "$FROM")'"
;;
esac
[ -z "$file_type" ] && file_type=$(get_type "$command")
decompressor=$(get_decompressor "$file_type")
if [ -z "${MAX_SIZE}" ]; then
eval "$command" | \
tee >( hasher $HASH_TYPE) | \
decompress "$decompressor" "$TO"
if [ "$?" != "0" -o "$PIPESTATUS" != "0" ]; then
echo "Error copying" >&2
exit -1
fi
else
# Order of the 'head' command is here on purpose:
# 1. We want to download more bytes than needed to get a requested
# number of bytes on the output. Decompressor may need more
# data to decompress the stream.
# 2. Decompressor command is also misused to detect SIGPIPE error.
eval "$command" | \
decompress "$decompressor" "$TO" 2>/dev/null | \
head -c "${MAX_SIZE}"
# Following table shows exit codes of each command
# in the pipe for various scenarios:
#
# ----------------------------------------------------
# | $COMMAND | TYPE | PIPESTATUS | BEHAVIOUR
# ----------------------------------------------------
# | cat | partial | 141 141 0 | OK
# | cat | full | 0 0 0 | OK
# | cat | error | 1 0 0 | fail
# | curl | partial | 23 141 0 | OK
# | curl | full | 0 0 0 | OK
# | curl | error | 22 0 0 | fail
# | ssh | partial | 255 141 0 | OK
# | ssh | full | 0 0 0 | OK
# | ssh | error ssh | 255 0 0 | fail
# | ssh | error ssh cat | 1 0 0 | fail
if [ \( "${PIPESTATUS[0]}" != '0' -a "${PIPESTATUS[1]}" = '0' \) \
-o \( "${PIPESTATUS[1]}" != '0' -a "${PIPESTATUS[1]}" != '141' \) \
-o \( "${PIPESTATUS[2]}" != "0" \) ];
then
echo "Error copying" >&2
exit -1
fi
fi
if [ -n "$HASH_TYPE" ]; then
HASH_RESULT=$( cat $HASH_FILE)
rm $HASH_FILE
if [ "$HASH_RESULT" != "$HASH" ]; then
echo "Hash does not match" >&2
exit -1
fi
fi
# Unarchive only if the destination is filesystem
if [ "$TO" != "-" ]; then
unarchive "$TO"
fi
# Perform any clean operation
if [ -n "${clean_command}" ]; then
eval "$clean_command"
fi

View File

@ -1,60 +0,0 @@
diff --git /var/lib/one/remotes/datastore/downloader.sh /var/lib/one/remotes/datastore/downloader.sh
index 9b75d8ee4b..09d2a5d41d 100755
--- /var/lib/one/remotes/datastore/downloader.sh
+++ /var/lib/one/remotes/datastore/downloader.sh
@@ -295,6 +295,45 @@ function get_rbd_cmd
echo "ssh '$(esc_sq "$DST_HOST")' \"$RBD export '$(esc_sq "$SOURCE")' -\""
}
+function get_vitastor_cmd
+{
+ local i j URL_ELEMENTS
+
+ FROM="$1"
+
+ URL_RB="$DRIVER_PATH/url.rb"
+
+ while IFS= read -r -d '' element; do
+ URL_ELEMENTS[i++]="$element"
+ done < <($URL_RB "$FROM" \
+ USER \
+ HOST \
+ SOURCE \
+ PARAM_DS \
+ PARAM_VITASTOR_CONF)
+
+ USER="${URL_ELEMENTS[j++]}"
+ DST_HOST="${URL_ELEMENTS[j++]}"
+ SOURCE="${URL_ELEMENTS[j++]}"
+ DS="${URL_ELEMENTS[j++]}"
+ VITASTOR_CONF="${URL_ELEMENTS[j++]}"
+
+ # Remove leading '/'
+ SOURCE="${SOURCE#/}"
+
+ if [ -n "$USER" ]; then
+ DST_HOST="$USER@$DST_HOST"
+ fi
+
+ local CLI
+ CLI="vitastor-cli"
+ if [ -n "$VITASTOR_CONF" ]; then
+ CLI="$CLI --config_path '$(esc_sq "${VITASTOR_CONF}")'"
+ fi
+
+ echo "ssh '$(esc_sq "$DST_HOST")' \"$CLI dd iimg='$(esc_sq "$SOURCE")'\""
+}
+
# Compare 2 version strings using sort -V
# Usage:
# verlte "3.2.9" "3.4.0"
@@ -424,6 +463,9 @@ s3://*)
rbd://*)
command="$(get_rbd_cmd "$FROM")"
;;
+vitastor://*)
+ command="$(get_vitastor_cmd "$FROM")"
+ ;;
vcenter://*)
command="$VAR_LOCATION/remotes/datastore/vcenter_downloader.rb '$(esc_sq "$FROM")'"
;;

View File

@ -1,114 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# This script is used to export an image to qcow2 file
# ------------ Set up the environment to source common tools ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh
# -------- Get rm and datastore arguments from OpenNebula core ------------
DRV_ACTION=`cat -`
ID=$1
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
unset i XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH \
/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \
/DS_DRIVER_ACTION_DATA/IMAGE/SIZE \
/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5 \
/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/SHA1 \
/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/FORMAT \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF)
unset i
SRC="${XPATH_ELEMENTS[i++]}"
SIZE="${XPATH_ELEMENTS[i++]}"
MD5="${XPATH_ELEMENTS[i++]}"
SHA1="${XPATH_ELEMENTS[i++]}"
FORMAT="${XPATH_ELEMENTS[i++]:-raw}"
BRIDGE_LIST="${XPATH_ELEMENTS[i++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[i++]}"
DST_HOST=`get_destination_host $ID`
if [ -z "$DST_HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi
IMPORT_SOURCE="vitastor://$DST_HOST/$SRC"
IS_JOIN="?"
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path $VITASTOR_CONF"
IMPORT_SOURCE="${IMPORT_SOURCE}${IS_JOIN}VITASTOR_CONF=${VITASTOR_CONF}"
fi
# FIXME: this is inefficient - it pipes the image twice...
INFO_SCRIPT=$(cat <<EOF
if [ -z "$MD5" ]; then
CHECKSUM=\$(
$CLI dd iimg=${SRC} | ${MD5SUM} | cut -f1 -d' '
ps=\$PIPESTATUS
if [ "\$ps" != "0" ]; then
exit \$ps
fi
)
status=\$?
[ "\$status" != "0" ] && exit \$status
else
CHECKSUM="$MD5"
fi
if [ -z "\$CHECKSUM" ]; then
exit 1
fi
cat <<EOT
<MD5><![CDATA[\$CHECKSUM]]></MD5>
<SIZE><![CDATA[$SIZE]]></SIZE>
<FORMAT><![CDATA[${FORMAT}]]></FORMAT>
EOT
EOF
)
INFO=$(ssh_monitor_and_log "$DST_HOST" "$INFO_SCRIPT" "Image info script" 2>&1)
INFO_STATUS=$?
if [ "$INFO_STATUS" != "0" ]; then
echo "$INFO"
exit $INFO_STATUS
fi
cat <<EOF
<IMPORT_INFO>
<IMPORT_SOURCE><![CDATA[$IMPORT_SOURCE]]></IMPORT_SOURCE>
$INFO
<DISPOSE>NO</DISPOSE>
</IMPORT_INFO>"
EOF

View File

@ -1,124 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# This script is used to create a VM image (SRC) of size (SIZE) and formatted as (FS)
# -------- Set up the environment to source common tools & conf ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh
source ${DRIVER_PATH}/../../etc/datastore/datastore.conf
# -------- Get mkfs and datastore arguments from OpenNebula core ------------
DRV_ACTION=`cat -`
ID=$1
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
unset i XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/RESTRICTED_DIRS \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/SAFE_DIRS \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/POOL_NAME \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/IMAGE_PREFIX \
/DS_DRIVER_ACTION_DATA/IMAGE/FORMAT \
/DS_DRIVER_ACTION_DATA/IMAGE/SIZE \
/DS_DRIVER_ACTION_DATA/IMAGE/FS \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF)
unset i
BASE_PATH="${XPATH_ELEMENTS[i++]}"
RESTRICTED_DIRS="${XPATH_ELEMENTS[i++]}"
SAFE_DIRS="${XPATH_ELEMENTS[i++]}"
BRIDGE_LIST="${XPATH_ELEMENTS[i++]}"
POOL_NAME="${XPATH_ELEMENTS[i++]}"
IMAGE_PREFIX="${XPATH_ELEMENTS[i++]:-one}"
FORMAT="${XPATH_ELEMENTS[i++]}"
SIZE="${XPATH_ELEMENTS[i++]}"
FS="${XPATH_ELEMENTS[i++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[i++]}"
DST_HOST=`get_destination_host $ID`
if [ -z "$DST_HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi
CLI=
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
if [ -n "$POOL_NAME" ]; then
CLI="$CLI --pool ${POOL_NAME}"
fi
set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS"
IMAGE_NAME="${IMAGE_PREFIX}-${ID}"
# ------------ Image to save_as disk, no need to create a new image ------------
if [ "$FORMAT" = "save_as" ]; then
echo "$IMAGE_NAME"
exit 0
fi
# ------------ Create the image in the repository ------------
# FIXME: Duplicate code with tm/vitastor/mkimage
MKIMAGE_CMD=$(cat <<EOF
set -e -o pipefail
export PATH=/usr/sbin:/sbin:\$PATH
vitastor-cli $CLI create --pool "${POOL_NAME}" "$IMAGE_NAME" --size "${SIZE}M"
EOF
)
if [ -n "$FS" -o "$FORMAT" = "swap" ]; then
MKFS_CMD=`mkfs_command '$NBD' raw "$SIZE" "$SUPPORTED_FS" "$FS" "$FS_OPTS" | grep -v $QEMU_IMG`
fi
MKIMAGE_CMD=$(cat <<EOF
set -e -o pipefail
export PATH=/usr/sbin:/sbin:\$PATH
vitastor-cli $CLI create --pool "${POOL_NAME}" "$IMAGE_NAME" --size "${SIZE}M"
EOF
)
if [ ! -z $FS ]; then
set -e -o pipefail
IMAGE_HASH=`generate_image_hash`
FS_OPTS=$(eval $(echo "echo \$FS_OPTS_$FS"))
MKFS_CMD=`mkfs_command '$NBD' raw "$SIZE" "$SUPPORTED_FS" "$FS" "$FS_OPTS" | grep -v $QEMU_IMG`
MKIMAGE_CMD=$(cat <<EOF
$MKIMAGE_CMD
NBD=\$(sudo vitastor-nbd $CLI map --image "$IMAGE_NAME")
trap "sudo vitastor-nbd $CLI unmap \$NBD" EXIT
$MKFS_CMD
EOF
)
fi
ssh_exec_and_log "$DST_HOST" "$MKIMAGE_CMD" "Error registering $IMAGE_NAME in $DST_HOST"
echo "$IMAGE_NAME"

View File

@ -1,64 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# This script is used to monitor the free and used space of a datastore
# -------- Set up the environment to source common tools & conf ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../../datastore/libfs.sh
# -------- Get datastore arguments from OpenNebula core ------------
DRV_ACTION=`cat -`
ID=$1
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb -b $DRV_ACTION"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/POOL_NAME \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF)
BRIDGE_LIST="${XPATH_ELEMENTS[j++]}"
POOL_NAME="${XPATH_ELEMENTS[j++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
HOST=`get_destination_host`
if [ -z "$HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
# ------------ Compute datastore usage -------------
MONITOR_SCRIPT=$(cat <<EOF
vitastor-cli df --json | jq -r '.[] | select(.name == "${POOL_NAME}") |
"TOTAL_MB="+(.total_raw/.raw_to_usable/1024/1024 | tostring)+
"\nUSED_MB="+(.used_raw/.raw_to_usable/1024/1024 | tostring)+
"\nFREE_MB="+(.max_available/1024/1024 | tostring)'
EOF
)
ssh_monitor_and_log $HOST "$MONITOR_SCRIPT 2>&1" "Error monitoring ${POOL_NAME} in $HOST"

View File

@ -1,73 +0,0 @@
diff --git /etc/one/oned.conf /etc/one/oned.conf
index be02d646a8..27f876ec36 100644
--- /etc/one/oned.conf
+++ /etc/one/oned.conf
@@ -481,7 +481,7 @@ VM_MAD = [
NAME = "kvm",
SUNSTONE_NAME = "KVM",
EXECUTABLE = "one_vmm_exec",
- ARGUMENTS = "-t 15 -r 0 kvm -p",
+ ARGUMENTS = "-t 15 -r 0 kvm -p -l deploy=deploy.vitastor",
DEFAULT = "vmm_exec/vmm_exec_kvm.conf",
TYPE = "kvm",
KEEP_SNAPSHOTS = "yes",
@@ -592,7 +592,7 @@ VM_MAD = [
TM_MAD = [
EXECUTABLE = "one_tm",
- ARGUMENTS = "-t 15 -d dummy,lvm,shared,fs_lvm,fs_lvm_ssh,qcow2,ssh,ceph,dev,vcenter,iscsi_libvirt"
+ ARGUMENTS = "-t 15 -d dummy,lvm,shared,fs_lvm,fs_lvm_ssh,qcow2,ssh,ceph,vitastor,dev,vcenter,iscsi_libvirt"
]
#*******************************************************************************
@@ -612,7 +612,7 @@ TM_MAD = [
DATASTORE_MAD = [
EXECUTABLE = "one_datastore",
- ARGUMENTS = "-t 15 -d dummy,fs,lvm,ceph,dev,iscsi_libvirt,vcenter,restic,rsync -s shared,ssh,ceph,fs_lvm,fs_lvm_ssh,qcow2,vcenter"
+ ARGUMENTS = "-t 15 -d dummy,fs,lvm,ceph,vitastor,dev,iscsi_libvirt,vcenter,restic,rsync -s shared,ssh,ceph,vitastor,fs_lvm,fs_lvm_ssh,qcow2,vcenter"
]
#*******************************************************************************
@@ -1050,6 +1050,9 @@ INHERIT_DATASTORE_ATTR = "VCENTER_DS_IMAGE_DIR"
INHERIT_DATASTORE_ATTR = "VCENTER_DS_VOLATILE_DIR"
INHERIT_DATASTORE_ATTR = "VCENTER_INSTANCE_ID"
+INHERIT_DATASTORE_ATTR = "VITASTOR_CONF"
+INHERIT_DATASTORE_ATTR = "IMAGE_PREFIX"
+
INHERIT_IMAGE_ATTR = "DISK_TYPE"
INHERIT_IMAGE_ATTR = "VCENTER_ADAPTER_TYPE"
INHERIT_IMAGE_ATTR = "VCENTER_DISK_TYPE"
@@ -1180,6 +1183,14 @@ TM_MAD_CONF = [
CLONE_TARGET_SHARED = "SELF", DISK_TYPE_SHARED = "RBD"
]
+TM_MAD_CONF = [
+ NAME = "vitastor", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES",
+ DS_MIGRATE = "NO", DRIVER = "raw", ALLOW_ORPHANS="format",
+ TM_MAD_SYSTEM = "ssh,shared", LN_TARGET_SSH = "SYSTEM", CLONE_TARGET_SSH = "SYSTEM",
+ DISK_TYPE_SSH = "FILE", LN_TARGET_SHARED = "NONE",
+ CLONE_TARGET_SHARED = "SELF", DISK_TYPE_SHARED = "FILE"
+]
+
TM_MAD_CONF = [
NAME = "iscsi_libvirt", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES",
DS_MIGRATE = "NO", DRIVER = "raw"
@@ -1263,9 +1274,16 @@ DS_MAD_CONF = [
NAME = "ceph",
REQUIRED_ATTRS = "DISK_TYPE,BRIDGE_LIST",
PERSISTENT_ONLY = "NO",
MARKETPLACE_ACTIONS = "export"
+]
+
+DS_MAD_CONF = [
+ NAME = "vitastor",
+ REQUIRED_ATTRS = "DISK_TYPE,BRIDGE_LIST",
+ PERSISTENT_ONLY = "NO",
+ MARKETPLACE_ACTIONS = "export"
]
DS_MAD_CONF = [
NAME = "dev", REQUIRED_ATTRS = "DISK_TYPE", PERSISTENT_ONLY = "YES"
]

View File

@ -1,115 +0,0 @@
#!/usr/bin/env python3
# Patch /etc/one/oned.conf for Vitastor support
# -s = also enable save.vitastor/restore.vitastor overrides
import re
import os
import sys
class Fixer:
save_restore = 0
def require_sub_cb(self, m, cb):
self.found = 1
return cb(m)
def require_sub(self, regexp, cb, text, error):
self.found = 0
new_text = re.sub(regexp, lambda m: self.require_sub_cb(m, cb), text)
if not self.found and error:
self.errors.append(error)
return new_text
def fix(self, oned_conf):
self.errors = []
self.kvm_found = 0
oned_conf = self.require_sub(r'((?:^|\n)[ \t]*VM_MAD\s*=\s*\[)([^\]]+)\]', lambda m: m.group(1)+self.fix_vm_mad(m.group(2))+']', oned_conf, 'VM_MAD not found')
if not self.kvm_found:
self.errors.append("VM_MAD[NAME=kvm].ARGUMENTS not found")
oned_conf = self.require_sub(r'((?:^|\n)[ \t]*TM_MAD\s*=\s*\[)([^\]]+)\]', lambda m: m.group(1)+self.fix_tm_mad(m.group(2))+']', oned_conf, 'TM_MAD not found')
oned_conf = self.require_sub(r'((?:^|\n)[ \t]*DATASTORE_MAD\s*=\s*\[)([^\]]+)\]', lambda m: m.group(1)+self.fix_datastore_mad(m.group(2))+']', oned_conf, 'DATASTORE_MAD not found')
if oned_conf[-1:] != '\n':
oned_conf += '\n'
if not re.compile(r'(^|\n)[ \t]*INHERIT_DATASTORE_ATTR\s*=\s*"VITASTOR_CONF"').search(oned_conf):
oned_conf += '\nINHERIT_DATASTORE_ATTR="VITASTOR_CONF"\n'
if not re.compile(r'(^|\n)[ \t]*INHERIT_DATASTORE_ATTR\s*=\s*"IMAGE_PREFIX"').search(oned_conf):
oned_conf += '\nINHERIT_DATASTORE_ATTR="IMAGE_PREFIX"\n'
if not re.compile(r'(^|\n)[ \t]*TM_MAD_CONF\s*=\s*\[[^\]]*NAME\s*=\s*"vitastor"').search(oned_conf):
oned_conf += ('\nTM_MAD_CONF = [\n'+
' NAME = "vitastor", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES",\n'+
' DS_MIGRATE = "NO", DRIVER = "raw", ALLOW_ORPHANS="format",\n'+
' TM_MAD_SYSTEM = "ssh,shared", LN_TARGET_SSH = "SYSTEM", CLONE_TARGET_SSH = "SYSTEM",\n'+
' DISK_TYPE_SSH = "FILE", LN_TARGET_SHARED = "NONE",\n'+
' CLONE_TARGET_SHARED = "SELF", DISK_TYPE_SHARED = "FILE"\n'+
']\n')
if not re.compile(r'(^|\n)[ \t]*DS_MAD_CONF\s*=\s*\[[^\]]*NAME\s*=\s*"vitastor"').search(oned_conf):
oned_conf += ('\nDS_MAD_CONF = [\n'+
' NAME = "vitastor",\n'+
' REQUIRED_ATTRS = "DISK_TYPE,BRIDGE_LIST",\n'+
' PERSISTENT_ONLY = "NO",\n'+
' MARKETPLACE_ACTIONS = "export"\n'+
']\n')
return oned_conf
def fix_vm_mad(self, vm_mad_params):
if re.compile(r'\bNAME\s*=\s*"kvm"').search(vm_mad_params):
vm_mad_params = re.sub(r'\b(ARGUMENTS\s*=\s*")([^"]+)"', lambda m: m.group(1)+self.fix_vm_mad_args(m.group(2))+'"', vm_mad_params)
self.kvm_found = 1
return vm_mad_params
def fix_vm_mad_args(self, args):
args = self.fix_vm_mad_override(args, 'deploy')
if self.save_restore:
args = self.fix_vm_mad_override(args, 'save')
args = self.fix_vm_mad_override(args, 'restore')
return args
def fix_vm_mad_override(self, args, override):
m = re.compile(r'-l (\S+)').search(args)
if m and re.compile(override+'='+override+'.vitastor').search(m.group(1)):
return args
elif m and re.compile(override+'=').search(m.group(1)):
self.errors.append(override+"= is already overridden in -l option in VM_MAD[NAME=kvm].ARGUMENTS")
return args
elif m:
return self.require_sub(r'-l (\S+)', lambda m: '-l '+m.group(1)+','+override+'='+override+'.vitastor', args, '-l option not found in VM_MAD[NAME=kvm].ARGUMENTS')
else:
return args+' -l '+override+'='+override+'.vitastor'
def fix_tm_mad(self, params):
return self.require_sub(r'\b(ARGUMENTS\s*=\s*")([^"]+)"', lambda m: m.group(1)+self.fix_tm_mad_args('d', m.group(2), "TM_MAD")+'"', params, "TM_MAD.ARGUMENTS not found")
def fix_tm_mad_args(self, opt, args, v):
return self.require_sub('(-'+opt+r') (\S+)', lambda m: self.fix_tm_mad_arg(m), args, "-"+opt+" option not found in "+v+".ARGUMENTS")
def fix_tm_mad_arg(self, m):
a = m.group(2).split(',')
if 'vitastor' not in a:
a += [ 'vitastor' ]
return m.group(1)+' '+(','.join(a))
def fix_datastore_mad(self, params):
params = self.require_sub(r'\b(ARGUMENTS\s*=\s*")([^"]+)"', lambda m: m.group(1)+self.fix_tm_mad_args('d', m.group(2), "DATASTORE_MAD")+'"', params, "DATASTORE_MAD.ARGUMENTS not found")
return self.require_sub(r'\b(ARGUMENTS\s*=\s*")([^"]+)"', lambda m: m.group(1)+self.fix_tm_mad_args('s', m.group(2), "DATASTORE_MAD")+'"', params, "")
fixer = Fixer()
oned_conf_file = ''
for arg in sys.argv[1:]:
if arg == '-s':
fixer.save_restore = 1
else:
oned_conf_file = arg
break
if not oned_conf_file:
sys.stderr.write("USAGE: ./patch-oned-conf.py [-s] /etc/one/oned.conf\n-s means also enable save.vitastor/restore.vitastor overrides\n")
sys.exit(1)
with open(oned_conf_file, 'r') as fd:
oned_conf = fd.read()
new_conf = fixer.fix(oned_conf)
if new_conf != oned_conf:
os.rename(oned_conf_file, oned_conf_file+'.bak')
with open(oned_conf_file, 'w') as fd:
fd.write(new_conf)
if len(fixer.errors) > 0:
sys.stderr.write("ERROR: Failed to patch "+oned_conf_file+", patch it manually. Errors:\n- "+('\n- '.join(fixer.errors))+'\n')
sys.exit(1)

View File

@ -1,63 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# This script is used to remove a VM image from the image repository
# ------------ Set up the environment to source common tools ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh
# -------- Get rm and datastore arguments from OpenNebula core ------------
DRV_ACTION=`cat -`
ID=$1
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH \
/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF)
IMAGE_NAME="${XPATH_ELEMENTS[j++]}"
BRIDGE_LIST="${XPATH_ELEMENTS[j++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
DST_HOST=`get_destination_host $ID`
if [ -z "$DST_HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
# -------- Remove Image from Datastore ------------
log "Removing $IMAGE_NAME from the image repository in $DST_HOST"
DELETE_CMD=$(cat <<EOF
$CLI rm $IMAGE_NAME
EOF
)
ssh_exec_and_log "$DST_HOST" "$DELETE_CMD" "Error deleting $IMAGE_NAME in $DST_HOST"

View File

@ -1,64 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# This script is used to delete a snapshot of an image
# -------- Set up the environment to source common tools & conf ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh
# -------- Get image and datastore arguments from OpenNebula core ------------
DRV_ACTION=`cat -`
ID=$1
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
unset i XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \
/DS_DRIVER_ACTION_DATA/IMAGE/TARGET_SNAPSHOT \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF)
unset i
BRIDGE_LIST="${XPATH_ELEMENTS[i++]}"
IMAGE_NAME="${XPATH_ELEMENTS[i++]}"
SNAP_ID="${XPATH_ELEMENTS[i++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[i++]}"
DST_HOST=`get_destination_host $ID`
if [ -z "$DST_HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
SNAP_DELETE_CMD=$(cat <<EOF
$CLI rm ${IMAGE_NAME}@${SNAP_ID}
EOF
)
ssh_exec_and_log "$DST_HOST" "$SNAP_DELETE_CMD" "Error deleting snapshot $IMAGE_NAME-$SNAP_ID@$SNAP_ID"

View File

@ -1,69 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# This script is used to flatten a snapshot of a persistent image
# -------- Set up the environment to source common tools & conf ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh
# -------- Get image and datastore arguments from OpenNebula core ------------
DRV_ACTION=`cat -`
ID=$1
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
unset i XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/POOL_NAME \
/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \
/DS_DRIVER_ACTION_DATA/IMAGE/TARGET_SNAPSHOT \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF)
unset i
BRIDGE_LIST="${XPATH_ELEMENTS[i++]}"
POOL_NAME="${XPATH_ELEMENTS[i++]}"
IMAGE_NAME="${XPATH_ELEMENTS[i++]}"
SNAP_ID="${XPATH_ELEMENTS[i++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[i++]}"
DST_HOST=`get_destination_host $ID`
if [ -z "$DST_HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
SNAP_FLATTEN_CMD=$(cat <<EOF
set -e
$CLI flatten "$IMAGE_NAME@$SNAP_ID"
$CLI modify "$IMAGE_NAME@$SNAP_ID" --rename "$IMAGE_NAME"
$CLI rm --matching "$IMAGE_NAME@*"
EOF
)
ssh_exec_and_log "$DST_HOST" "$SNAP_FLATTEN_CMD" "Error flattening snapshot $SNAP_ID for $IMAGE_NAME"

View File

@ -1,72 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# This script is used to revert a snapshot of an image
# -------- Set up the environment to source common tools & conf ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
LIB_LOCATION=$ONE_LOCATION/lib
fi
. $LIB_LOCATION/sh/scripts_common.sh
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh
# -------- Get image and datastore arguments from OpenNebula core ------------
DRV_ACTION=`cat -`
ID=$1
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
unset i XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/POOL_NAME \
/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \
/DS_DRIVER_ACTION_DATA/IMAGE/TARGET_SNAPSHOT \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF)
unset i
BRIDGE_LIST="${XPATH_ELEMENTS[i++]}"
POOL_NAME="${XPATH_ELEMENTS[i++]}"
IMAGE_NAME="${XPATH_ELEMENTS[i++]}"
SNAP_ID="${XPATH_ELEMENTS[i++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[i++]}"
DST_HOST=`get_destination_host $ID`
if [ -z "$DST_HOST" ]; then
error_message "Datastore template missing 'BRIDGE_LIST' attribute."
exit -1
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
if [ -n "$POOL_NAME" ]; then
CLI="$CLI --pool ${POOL_NAME}"
fi
SNAP_REVERT_CMD=$(cat <<EOF
$CLI rm ${IMAGE_NAME}.flatten || true
$CLI create --pool "${POOL_NAME}" --parent ${IMAGE_NAME}@${SNAP_ID} ${IMAGE_NAME}.flatten
$CLI rm ${IMAGE_NAME} || true
$CLI modify ${IMAGE_NAME}.flatten --rename ${IMAGE_NAME}
EOF
)
ssh_exec_and_log "$DST_HOST" "$SNAP_REVERT_CMD" "Error reverting snapshot $SNAP_ID for $IMAGE_NAME"

View File

@ -1 +0,0 @@
../ceph/stat

View File

@ -1,12 +0,0 @@
diff --git /etc/one/vmm_exec/vmm_execrc /etc/one/vmm_exec/vmm_execrc
index e210526e63..cb51d3b5e8 100644
--- /etc/one/vmm_exec/vmm_execrc
+++ /etc/one/vmm_exec/vmm_execrc
@@ -1,6 +1,6 @@
# Space separated list of VMM-TM pairs that support live disk snapshots. VMM
# and TM must be separated by '-'
-LIVE_DISK_SNAPSHOTS="kvm-qcow2 kvm-shared kvm-ceph kvm-ssh qemu-qcow2 qemu-shared qemu-ceph qemu-ssh"
+LIVE_DISK_SNAPSHOTS="kvm-qcow2 kvm-shared kvm-ceph kvm-vitastor kvm-ssh qemu-qcow2 qemu-shared qemu-ceph qemu-ssh"
# Space separated list VNM_MAD-ACTION pairs that run locally
VNMAD_LOCAL_ACTIONS="elastic-post elastic-clean"

View File

@ -1,97 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# clone fe:SOURCE host:remote_system_ds/disk.i size
# - fe is the front-end hostname
# - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk
# - host is the target host to deploy the VM
# - remote_system_ds is the path for the system datastore in the host
SRC=$1
DST=$2
VM_ID=$3
DS_ID=$4
#--------------------------------------------------------------------------------
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
LIB_LOCATION=/usr/lib/one
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
LIB_LOCATION=$ONE_LOCATION/lib
fi
DRIVER_PATH=$(dirname $0)
source $TMCOMMON
#-------------------------------------------------------------------------------
# Compute the destination image name
#-------------------------------------------------------------------------------
DST_HOST=`arg_host $DST`
SRC_PATH=`arg_path $SRC`
DST_PATH=`arg_path $DST`
DST_DIR=`dirname $DST_PATH`
DISK_ID=$(echo $DST|awk -F. '{print $NF}')
VM_DST="${SRC_PATH}-${VM_ID}-${DISK_ID}"
DST_DS_ID=`echo $DST | sed s#//*#/#g | awk -F/ '{print $(NF-2)}'`
#-------------------------------------------------------------------------------
# Get Image information
#-------------------------------------------------------------------------------
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onevm show -x $VM_ID | $XPATH \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/VITASTOR_CONF \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SIZE)
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
SIZE="${XPATH_ELEMENTS[j++]}"
#-------------------------------------------------------------------------------
# Get Datastore information
#-------------------------------------------------------------------------------
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onedatastore show -x $DST_DS_ID | $XPATH \
/DATASTORE/TEMPLATE/POOL_NAME)
POOL_NAME="${XPATH_ELEMENTS[j++]}"
disable_local_monitoring $DST_HOST $DST_DIR
#-------------------------------------------------------------------------------
# Clone the image
#-------------------------------------------------------------------------------
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
if [ -n "$POOL_NAME" ]; then
CLI="$CLI --pool ${POOL_NAME}"
fi
CLONE_CMD=$(cat <<EOF
$CLI create --parent $SRC_PATH --size ${SIZE}M $VM_DST
EOF
)
ssh_exec_and_log "$DST_HOST" "$CLONE_CMD" "Error cloning $SRC_PATH to $VM_DST in $DST_HOST"
exit 0

View File

@ -1 +0,0 @@
../ceph/context

View File

@ -1,113 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# cpds host:remote_system_ds/disk.i fe:SOURCE snapid vmid dsid
# - fe is the front-end hostname
# - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk
# - host is the target host to deploy the VM
# - remote_system_ds is the path for the system datastore in the host
# - snapid is the snapshot id. "-1" for none
SRC=$1
DST=$2
SNAP_ID=$3
VM_ID=$4
DS_ID=$5
#--------------------------------------------------------------------------------
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
LIB_LOCATION=/usr/lib/one
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
LIB_LOCATION=$ONE_LOCATION/lib
fi
DRIVER_PATH=$(dirname $0)
source $TMCOMMON
source ${DRIVER_PATH}/../../datastore/libfs.sh
source ${DRIVER_PATH}/../../etc/vmm/kvm/kvmrc
#-------------------------------------------------------------------------------
# Set dst path and dir
#-------------------------------------------------------------------------------
SRC_HOST=`arg_host $SRC`
SRC_PATH=`arg_path $SRC`
#-------------------------------------------------------------------------------
# Get Image information
#-------------------------------------------------------------------------------
DISK_ID=$(echo "$SRC_PATH" | $AWK -F. '{print $NF}')
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onevm show -x $VM_ID | $XPATH \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/VITASTOR_CONF \
/VM/LCM_STATE)
SRC_IMAGE="${XPATH_ELEMENTS[j++]}"
CLONE="${XPATH_ELEMENTS[j++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
LCM_STATE="${XPATH_ELEMENTS[j++]}"
#-------------------------------------------------------------------------------
# Get Datastore information
#-------------------------------------------------------------------------------
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onedatastore show -x $DS_ID | $XPATH \
/DATASTORE/TEMPLATE/POOL_NAME \
/DATASTORE/TEMPLATE/BRIDGE_LIST)
POOL_NAME="${XPATH_ELEMENTS[j++]}"
BRIDGE_LIST="${XPATH_ELEMENTS[j++]}"
#-------------------------------------------------------------------------------
# Copy Image back to the datastore
#-------------------------------------------------------------------------------
if [ "$CLONE" = "YES" ]; then
SRC_IMAGE="${SRC_IMAGE}-${VM_ID}-${DISK_ID}"
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
if [ -n "$POOL_NAME" ]; then
CLI="$CLI --pool ${POOL_NAME}"
fi
# Undeployed VM state, do not use front-end, choose host from bridge_list
if [ "$LCM_STATE" = '67' ] || [ "$LCM_STATE" = '68' ]; then
if [ -n "$BRIDGE_LIST" ]; then
SRC_HOST=`get_destination_host`
fi
fi
if [ "$SNAP_ID" != "-1" ]; then
SRC_IMAGE=$SRC_IMAGE@$SNAP_ID
fi
COPY_CMD=$(cat <<EOF
$CLI dd iimg=$SRC_IMAGE oimg=$DST
EOF
)
ssh_exec_and_log "$SRC_HOST" "$COPY_CMD" "Error cloning $SRC_IMAGE to $DST in $SRC_HOST"

View File

@ -1,139 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# DELETE <host:remote_system_ds/disk.i|host:remote_system_ds/>
# - host is the target host to deploy the VM
# - remote_system_ds is the path for the system datastore in the host
DST=$1
VM_ID=$2
DS_ID=$3
#--------------------------------------------------------------------------------
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
LIB_LOCATION=/usr/lib/one
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
LIB_LOCATION=$ONE_LOCATION/lib
fi
DRIVER_PATH=$(dirname $0)
source $TMCOMMON
source ${DRIVER_PATH}/../../datastore/libfs.sh
#-------------------------------------------------------------------------------
# Process destination
#-------------------------------------------------------------------------------
DST_PATH=`arg_path $DST`
DST_HOST=`arg_host $DST`
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
#-------------------------------------------------------------------------------
# Delete and exit if directory
#-------------------------------------------------------------------------------
if [ `is_disk $DST_PATH` -eq 0 ]; then
# Directory: delete checkpoint and directory
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onedatastore show -x $DS_ID | $XPATH \
/DATASTORE/TEMPLATE/SOURCE \
/DATASTORE/TEMPLATE/CLONE \
/DATASTORE/TEMPLATE/VITASTOR_CONF \
/DATASTORE/TEMPLATE/IMAGE_PREFIX \
/DATASTORE/TEMPLATE/POOL_NAME)
SRC="${XPATH_ELEMENTS[j++]}"
CLONE="${XPATH_ELEMENTS[j++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
IMAGE_PREFIX="${XPATH_ELEMENTS[j++]:-one}"
POOL_NAME="${XPATH_ELEMENTS[j++]}"
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
SRC_CHECKPOINT="${IMAGE_PREFIX}-sys-${VM_ID}-checkpoint"
ssh_exec_and_log "$DST_HOST" "$CLI rm $SRC_CHECKPOINT 2>/dev/null || exit 0" \
"Error deleting $SRC_CHECKPOINT in $DST_HOST"
log "Deleting $DST_PATH"
ssh_exec_and_log "$DST_HOST" "rm -rf $DST_PATH" "Error deleting $DST_PATH"
exit 0
fi
#-------------------------------------------------------------------------------
# Get Image information
#-------------------------------------------------------------------------------
DISK_ID=$(echo "$DST_PATH" | $AWK -F. '{print $NF}')
# Reads the disk parameters -- taken from image datastore
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onevm show -x $VM_ID | $XPATH \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/VITASTOR_CONF \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/IMAGE_PREFIX \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/POOL_NAME)
SRC="${XPATH_ELEMENTS[j++]}"
CLONE="${XPATH_ELEMENTS[j++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
IMAGE_PREFIX="${XPATH_ELEMENTS[j++]:-one}"
POOL_NAME="${XPATH_ELEMENTS[j++]}"
if is_undeployed "$VM_ID" "$DST_HOST"; then
# get BRIDGE_LIST from datastore
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
IFS= read -r -d '' BRIDGE_LIST < <(onedatastore show -x "$DS_ID" \
| $XPATH /DATASTORE/TEMPLATE/BRIDGE_LIST )
if [ -n "$BRIDGE_LIST" ]; then
DST_HOST=$(get_destination_host)
fi
fi
# No need to delete not cloned images
if [ "$CLONE" = "NO" ]; then
exit 0
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
if [ -n "$SRC" ]; then
# cloned, so the name will be "one-<imageid>-<vmid>-<diskid>"
SRC_IMAGE="${SRC}-${VM_ID}-${DISK_ID}"
else
# volatile
SRC_IMAGE="${IMAGE_PREFIX}-sys-${VM_ID}-${DISK_ID}"
fi
# Delete the image
log "Deleting $DST_PATH"
DELETE_CMD=$(cat <<EOF
$CLI rm $SRC_IMAGE
EOF
)
ssh_exec_and_log "$DST_HOST" "$DELETE_CMD" "Error deleting $SRC_IMAGE in $DST_HOST"

View File

@ -1 +0,0 @@
../ceph/failmigrate

View File

@ -1,16 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# <CLONE|LN>(.tm_mad_system) tm_mad fe:SOURCE host:remote_system_ds/disk.i vmid dsid
# LN = Attach disk to a VM (Vitastor doesn't need to do anything in this case)
SRC=$1
DST=$2
VM_ID=$3
DS_ID=$4
exit 0

View File

@ -1,120 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# mkimage size format host:remote_system_ds/disk.i vmid dsid
# - size in MB of the image
# - format for the image
# - host is the target host to deploy the VM
# - remote_system_ds is the path for the system datastore in the host
# - vmid is the id of the VM
# - dsid is the target datastore (0 is the system datastore)
SIZE=$1
FORMAT=$2
DST=$3
VMID=$4
DSID=$5
#-------------------------------------------------------------------------------
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
LIB_LOCATION=/usr/lib/one
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
LIB_LOCATION=$ONE_LOCATION/lib
fi
DRIVER_PATH=$(dirname $0)
source $TMCOMMON
source ${DRIVER_PATH}/../../etc/datastore/datastore.conf
source ${DRIVER_PATH}/../../datastore/libfs.sh
#-------------------------------------------------------------------------------
# Set dst path and dir
#-------------------------------------------------------------------------------
DST_PATH=`arg_path $DST`
DST_HOST=`arg_host $DST`
DST_DIR=`dirname $DST_PATH`
DISK_ID=$(echo $DST|awk -F. '{print $NF}')
#-------------------------------------------------------------------------------
# Get Image information
#-------------------------------------------------------------------------------
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onevm show -x $VMID | $XPATH \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/VITASTOR_CONF \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/POOL_NAME \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/IMAGE_PREFIX \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/FS)
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
POOL_NAME="${XPATH_ELEMENTS[j++]}"
IMAGE_PREFIX="${XPATH_ELEMENTS[j++]:-one}"
FS="${XPATH_ELEMENTS[j++]}"
CLI=
QEMU_ARG=""
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
QEMU_ARG=":config_path=${VITASTOR_CONF}"
fi
IMAGE_NAME="${IMAGE_PREFIX}-sys-${VMID}-${DISK_ID}"
ssh_make_path $DST_HOST $DST_DIR
set -e -o pipefail
# if user requested a swap or specifies a FS, we need to create a local
# formatted image and upload into existing Vitastor image
FS_OPTS=$(eval $(echo "echo \$FS_OPTS_$FS"))
MKIMAGE_CMD=$(cat <<EOF
set -e -o pipefail
export PATH=/usr/sbin:/sbin:\$PATH
vitastor-cli $CLI create --pool "${POOL_NAME}" "$IMAGE_NAME" --size "${SIZE}M"
EOF
)
if [ -n "$FS" -o "$FORMAT" = "swap" ]; then
MKFS_CMD=`mkfs_command '$NBD' raw "$SIZE" "$SUPPORTED_FS" "$FS" "$FS_OPTS" | grep -v $QEMU_IMG`
MKIMAGE_CMD=$(cat <<EOF
$MKIMAGE_CMD
NBD=\$(sudo vitastor-nbd $CLI map --image "$IMAGE_NAME")
trap "sudo vitastor-nbd $CLI unmap \$NBD" EXIT
$MKFS_CMD
EOF
)
fi
DELIMAGE_CMD=$(cat <<EOF
vitastor-cli $CLI rm "$IMAGE_NAME"
EOF
)
log "Making volatile disk of ${SIZE}M at $DST"
ssh_exec_and_log_no_error "$DST_HOST" "$MKIMAGE_CMD" "Error creating volatile disk.$DISK_ID ($IMAGE_NAME) in $DST_HOST in pool $POOL_NAME."
rc=$?
if [ $rc != 0 ]; then
ssh_exec_and_log_no_error "$DST_HOST" "$DELIMAGE_CMD" "Error removing image"
fi
exit $rc

View File

@ -1 +0,0 @@
../ceph/mkswap

View File

@ -1 +0,0 @@
../../datastore/vitastor/monitor

View File

@ -1 +0,0 @@
../ceph/mv

View File

@ -1,15 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# mvds host:remote_system_ds/disk.i fe:SOURCE vmid dsid
# - fe is the front-end hostname
# - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk
# - host is the target host to deploy the VM
# - remote_system_ds is the path for the system datastore in the host
# - vmid is the id of the VM
# - dsid is the target datastore (0 is the system datastore)
exit 0

View File

@ -1 +0,0 @@
postbackup_live

View File

@ -1 +0,0 @@
../ceph/postbackup_live

View File

@ -1 +0,0 @@
../ceph/postmigrate

View File

@ -1,152 +0,0 @@
#!/usr/bin/env ruby
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
ONE_LOCATION = ENV['ONE_LOCATION']
LIVE = ENV['LIVE']
if !ONE_LOCATION
RUBY_LIB_LOCATION = '/usr/lib/one/ruby'
GEMS_LOCATION = '/usr/share/one/gems'
VMDIR = '/var/lib/one'
CONFIG_FILE = '/var/lib/one/config'
else
RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby'
GEMS_LOCATION = ONE_LOCATION + '/share/gems'
VMDIR = ONE_LOCATION + '/var'
CONFIG_FILE = ONE_LOCATION + '/var/config'
end
# %%RUBYGEMS_SETUP_BEGIN%%
if File.directory?(GEMS_LOCATION)
real_gems_path = File.realpath(GEMS_LOCATION)
if !defined?(Gem) || Gem.path != [real_gems_path]
$LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ }
# Suppress warnings from Rubygems
# https://github.com/OpenNebula/one/issues/5379
begin
verb = $VERBOSE
$VERBOSE = nil
require 'rubygems'
Gem.use_paths(real_gems_path)
ensure
$VERBOSE = verb
end
end
end
# %%RUBYGEMS_SETUP_END%%
$LOAD_PATH << RUBY_LIB_LOCATION
require 'rexml/document'
require_relative '../lib/tm_action'
require_relative '../lib/kvm'
require_relative '../lib/datastore'
if LIVE
# TODO: fsfreeze for each hypervisor based on VM_MAD
include TransferManager::KVM
end
#-------------------------------------------------------------------------------
# BACKUP tm_mad host:remote_dir DISK_ID:...:DISK_ID deploy_id bjid vmid dsid
#-------------------------------------------------------------------------------
TransferManager::Datastore.load_env
vm_xml = STDIN.read
dir = ARGV[0].split ':'
disks = ARGV[1].split ':'
deploy_id = ARGV[2]
_bjid = ARGV[3]
vmid = ARGV[4]
_dsid = ARGV[5]
rhost = dir[0]
rdir = dir[1]
xml_doc = REXML::Document.new(vm_xml)
vm = xml_doc.root
ds = TransferManager::Datastore.from_vm_backup_ds(:vm_xml => vm_xml)
base_path = ENV['BACKUP_BASE_PATH']
bck_dir = if base_path
"#{base_path}/#{vmid}/backup"
else
"#{rdir}/backup"
end
snap_cmd = ''
expo_cmd = ''
clup_cmd = ''
vm.elements.each 'TEMPLATE/DISK' do |d|
did = d.elements['DISK_ID'].text
next unless disks.include? did
src = d.elements['SOURCE'].text
clon = d.elements['CLONE'].text
src_image = if clon == 'NO' then src else "#{src}-#{vmid}-#{did}" end
cmd = 'vitastor-cli'
qemu_arg = ''
if d.elements['VITASTOR_CONF']
cmd = cmd + ' --config_path ' + d.elements['VITASTOR_CONF']
qemu_arg += 'config_path='+d.elements['VITASTOR_CONF']+':'
end
draw = "#{bck_dir}/disk.#{did}.raw"
ddst = "#{bck_dir}/disk.#{did}.0"
expo_cmd << ds.cmd_confinement("qemu-img convert -m 4 -O qcow2 'vitastor:#{qemu_arg}image=#{src_image}' #{ddst}\n", rdir)
clup_cmd << "rm -f #{draw}\n"
rescue StandardError => e
STDERR.puts "Missing configuration attributes in DISK: #{e.message}"
exit(1)
end
if LIVE
freeze, thaw = fsfreeze(vm, deploy_id)
end
script = <<~EOS
set -ex -o pipefail
# Prepare backup folder
[ -d #{bck_dir} ] && rm -rf #{bck_dir}
mkdir -p #{bck_dir}
echo "#{Base64.encode64(vm_xml)}" > #{bck_dir}/vm.xml
#{freeze}
#{snap_cmd}
#{thaw}
#{expo_cmd}
#{clup_cmd}
EOS
rc = TransferManager::Action.ssh('prebackup_live',
:host => rhost,
:cmds => script,
:nostdout => false,
:nostderr => false
)
if rc.code != 0
STDERR.puts "Error preparing disk files: #{rc.stdout} #{rc.stderr}"
end
exit(rc.code)

View File

@ -1,8 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
export LIVE=1
`dirname $0`/prebackup $@

View File

@ -1 +0,0 @@
../ceph/premigrate

View File

@ -1,81 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# resize image size vmid
SRC=$1
SIZE=$2
VM_ID=$3
#--------------------------------------------------------------------------------
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
LIB_LOCATION=/usr/lib/one
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
LIB_LOCATION=$ONE_LOCATION/lib
fi
DRIVER_PATH=$(dirname $0)
source $TMCOMMON
#-------------------------------------------------------------------------------
# Set dst path and dir
#-------------------------------------------------------------------------------
SRC_HOST=`arg_host $SRC`
SRC_PATH=`arg_path $SRC`
#-------------------------------------------------------------------------------
# Get Image information
#-------------------------------------------------------------------------------
DISK_ID=$(echo "$SRC_PATH" | $AWK -F. '{print $NF}')
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onevm show -x $VM_ID | $XPATH \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/VITASTOR_CONF \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/IMAGE_PREFIX \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/PERSISTENT)
SRC_IMAGE="${XPATH_ELEMENTS[j++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
IMAGE_PREFIX="${XPATH_ELEMENTS[j++]:-one}"
PERSISTENT="${XPATH_ELEMENTS[j++]}"
if [ -n "${SRC_IMAGE}" ]; then
if [ "${PERSISTENT}" != 'YES' ]; then
SRC_IMAGE="${SRC_IMAGE}-${VM_ID}-${DISK_ID}"
fi
else
SRC_IMAGE="${IMAGE_PREFIX}-sys-${VM_ID}-${DISK_ID}"
fi
#-------------------------------------------------------------------------------
# Resize disk
#-------------------------------------------------------------------------------
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
RESIZE_CMD=$(cat <<EOF
$CLI modify --resize ${SIZE}M "$SRC_IMAGE"
EOF
)
ssh_exec_and_log "$SRC_HOST" "$RESIZE_CMD" "Error resizing disk $SRC_IMAGE"
exit 0

View File

@ -1,201 +0,0 @@
#!/usr/bin/env ruby
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
ONE_LOCATION = ENV['ONE_LOCATION']
if !ONE_LOCATION
RUBY_LIB_LOCATION = '/usr/lib/one/ruby'
GEMS_LOCATION = '/usr/share/one/gems'
VMDIR = '/var/lib/one'
CONFIG_FILE = '/var/lib/one/config'
else
RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby'
GEMS_LOCATION = ONE_LOCATION + '/share/gems'
VMDIR = ONE_LOCATION + '/var'
CONFIG_FILE = ONE_LOCATION + '/var/config'
end
# %%RUBYGEMS_SETUP_BEGIN%%
if File.directory?(GEMS_LOCATION)
real_gems_path = File.realpath(GEMS_LOCATION)
if !defined?(Gem) || Gem.path != [real_gems_path]
$LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ }
# Suppress warnings from Rubygems
# https://github.com/OpenNebula/one/issues/5379
begin
verb = $VERBOSE
$VERBOSE = nil
require 'rubygems'
Gem.use_paths(real_gems_path)
ensure
$VERBOSE = verb
end
end
end
# %%RUBYGEMS_SETUP_END%%
$LOAD_PATH << RUBY_LIB_LOCATION
require 'rexml/document'
require 'json'
require 'securerandom'
require_relative '../lib/tm_action'
require_relative '../lib/datastore'
def get_vitastor_disks(vm_xml)
vm_xml = REXML::Document.new(vm_xml) if vm_xml.is_a?(String)
vm = vm_xml.root
vmid = vm.elements['VMID'].text
indexed_disks = []
vm.elements.each('DISK[TM_MAD="vitastor"]') do |d|
disk = new(vmid, d)
indexed_disks[disk.id] = disk
end
indexed_disks
end
#-------------------------------------------------------------------------------
# RESTORE vm_id img_id inc_id disk_id
#-------------------------------------------------------------------------------
_dir = ARGV[0].split ':'
vm_id = ARGV[1]
bk_img_id = ARGV[2].to_i
inc_id = ARGV[3]
disk_id = ARGV[4].to_i
begin
action = TransferManager::Action.new(:action_name => 'restore',
:vm_id => vm_id)
# --------------------------------------------------------------------------
# Image & Datastore information
# --------------------------------------------------------------------------
bk_img = OpenNebula::Image.new_with_id(bk_img_id, action.one)
rc = bk_img.info
raise rc.message.to_s if OpenNebula.is_error?(rc)
bk_ds = TransferManager::Datastore.from_image_ds(:image => bk_img,
:client => action.one)
# --------------------------------------------------------------------------
# Backup information
# sample output: {"0":"rsync://100//0:3ffce7/var/lib/one/datastores/100/1/3ffce7/disk.0.0"}
# --------------------------------------------------------------------------
xml_data = <<~EOS
#{action.vm.to_xml}
#{bk_img.to_xml}
EOS
rc = bk_ds.action("ls -i #{inc_id}", xml_data)
raise 'cannot list backup contents' unless rc.code == 0
disk_urls = JSON.parse(rc.stdout)
disk_urls = disk_urls.select {|id, _url| id.to_i == disk_id } if disk_id != -1
# --------------------------------------------------------------------------
# Restore disk_urls in Host VM folder
# --------------------------------------------------------------------------
vitastor_disks = get_vitastor_disks(action.vm.template_xml)
success_disks = []
info = {}
disk_urls.each do |id, url|
vitastor_disk = vitastor_disks[id.to_i]
randsuffix = SecureRandom.hex(5)
vitastor_one_ds = OpenNebula::Datastore.new_with_id(
action.vm["/VM/TEMPLATE/DISK[DISK_ID = #{id}]/DATASTORE_ID"].to_i, action.one
)
vitastor_ds = TransferManager::Datastore.new(:ds => vitastor_one_ds, :client => action.one)
src_image = vitastor_disk.elements['SOURCE'].text
disk_id = vitastor_disk.elements['DISK_ID'].text
if vitastor_disk.elements['CLONE'].text == 'YES'
src_image += '-'+vm_id+'-'+disk_id
end
cli = 'vitastor-cli'
config_path = vitastor_disk.elements['VITASTOR_CONF']
qemu_args = ''
if config_path:
cli += ' --config_path "'+config_path.text+'"'
qemu_args += ':config_path='+config_path.text
info[vitastor_disk] = {
:br => vitastor_ds.pick_bridge,
:bak => "#{src_image}.backup.#{randsuffix}",
:old => "#{src_image}.old.#{randsuffix}",
:cli => cli,
:img => src_image,
}
upload_vitastor = <<~EOS
set -e
tmpimg="$(mktemp -t disk#{id}.XXXX)"
#{__dir__}/../../datastore/downloader.sh --nodecomp #{url} $tmpimg
#{cli} create -s $(qemu-img info --output json $tmpimg | jq -r '.["virtual-size"]') #{info[vitastor_disk][:bak]}
qemu-img convert -m 4 -O raw $tmpimg "vitastor:image=#{info[vitastor_disk][:bak]}#{qemu_args}"
rm -f $tmpimg
EOS
rc = action.ssh(:host => info[vitastor_disk][:br],
:cmds => upload_ceph,
:forward => false,
:nostdout => false,
:nostderr => false)
break if rc.code != 0
success_disks << vitastor_disk
end
# Rollback and raise error if it was unable to backup all disks
if success_disks.length != disk_urls.length
success_disks.each do |vitastor_disk|
cleanup = <<~EOS
#{info[vitastor_disk][:cli]} rm #{info[vitastor_disk][:bak]}
EOS
action.ssh(:host => info[vitastor_disk][:br],
:cmds => cleanup,
:forward => false,
:nostdout => false,
:nostderr => false)
end
raise "error uploading backup disk to Vitastor (#{success_disks.length}/#{disk_urls.length})"
end
# --------------------------------------------------------------------------
# Replace VM disk_urls with backup copies (~prolog)
# --------------------------------------------------------------------------
success_disks.each do |vitastor_disk|
move = <<~EOS
set -e
#{info[vitastor_disk][:cli]} mv #{info[vitastor_disk][:img]} #{info[vitastor_disk][:old]}
#{info[vitastor_disk][:cli]} mv #{info[vitastor_disk][:bak]} #{info[vitastor_disk][:img]}
#{info[vitastor_disk][:cli]} rm --matching "#{info[vitastor_disk][:img]}@*"
#{info[vitastor_disk][:cli]} rm #{info[vitastor_disk][:old]}
EOS
rc = action.ssh(:host => info[vitastor_disk][:br],
:cmds => move,
:forward => false,
:nostdout => false,
:nostderr => false)
warn 'cannot restore disk backup' if rc.code != 0
end
rescue StandardError => e
STDERR.puts "Error restoring VM disks: #{e.message}"
exit(1)
end

View File

@ -1,78 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# snap_create host:parent_image snap_id vmid ds_id
SRC=$1
SNAP_ID=$2
VM_ID=$3
DS_ID=$4
#--------------------------------------------------------------------------------
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
LIB_LOCATION=/usr/lib/one
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
LIB_LOCATION=$ONE_LOCATION/lib
fi
DRIVER_PATH=$(dirname $0)
source $TMCOMMON
#-------------------------------------------------------------------------------
# Set dst path and dir
#-------------------------------------------------------------------------------
SRC_HOST=`arg_host $SRC`
SRC_PATH=`arg_path $SRC`
#-------------------------------------------------------------------------------
# Get Image information
#-------------------------------------------------------------------------------
DISK_ID=$(echo "$SRC_PATH" | $AWK -F. '{print $NF}')
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onevm show -x $VM_ID | $XPATH \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/VITASTOR_CONF \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
SRC_IMAGE="${XPATH_ELEMENTS[j++]}"
CLONE="${XPATH_ELEMENTS[j++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
TYPE="${XPATH_ELEMENTS[j++]}"
if [ "$CLONE" = "YES" ]; then
SRC_IMAGE="${SRC_IMAGE}-${VM_ID}-${DISK_ID}"
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
#-------------------------------------------------------------------------------
# Create snapshots
#-------------------------------------------------------------------------------
SNAP_CREATE_CMD=$(cat <<EOF
$CLI snap-create "$SRC_IMAGE@$SNAP_ID"
EOF
)
ssh_exec_and_log "$SRC_HOST" "$SNAP_CREATE_CMD" "Error creating snapshot $SRC_IMAGE@$SNAP_ID"
exit 0

View File

@ -1 +0,0 @@
snap_create

View File

@ -1,75 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# snap_delete host:parent_image snap_id vmid ds_id
SRC=$1
SNAP_ID=$2
VM_ID=$3
DS_ID=$4
# FIXME: copypaste below, down to "delete snapshot"
#--------------------------------------------------------------------------------
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
LIB_LOCATION=/usr/lib/one
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
LIB_LOCATION=$ONE_LOCATION/lib
fi
DRIVER_PATH=$(dirname $0)
source $TMCOMMON
#-------------------------------------------------------------------------------
# Set dst path and dir
#-------------------------------------------------------------------------------
SRC_HOST=`arg_host $SRC`
SRC_PATH=`arg_path $SRC`
#-------------------------------------------------------------------------------
# Get Image information
#-------------------------------------------------------------------------------
DISK_ID=$(echo "$SRC_PATH" | $AWK -F. '{print $NF}')
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onevm show -x $VM_ID | $XPATH \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/VITASTOR_CONF )
SRC_IMAGE="${XPATH_ELEMENTS[j++]}"
CLONE="${XPATH_ELEMENTS[j++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
if [ "$CLONE" = "YES" ]; then
SRC_IMAGE="${SRC_IMAGE}-${VM_ID}-${DISK_ID}"
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
#-------------------------------------------------------------------------------
# Delete snapshot
#-------------------------------------------------------------------------------
SNAP_DELETE_CMD=$(cat <<EOF
$CLI rm "$SRC_IMAGE@$SNAP_ID"
EOF
)
ssh_exec_and_log "$SRC_HOST" "$SNAP_DELETE_CMD" "Error deleting snapshot $SRC_IMAGE@$SNAP_ID"

View File

@ -1,79 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
# snap_revert host:parent_image snap_id vmid ds_id
SRC=$1
SNAP_ID=$2
VM_ID=$3
DS_ID=$4
#--------------------------------------------------------------------------------
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
LIB_LOCATION=/usr/lib/one
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
LIB_LOCATION=$ONE_LOCATION/lib
fi
DRIVER_PATH=$(dirname $0)
source $TMCOMMON
#-------------------------------------------------------------------------------
# Set dst path and dir
#-------------------------------------------------------------------------------
SRC_HOST=`arg_host $SRC`
SRC_PATH=`arg_path $SRC`
#-------------------------------------------------------------------------------
# Get Image information
#-------------------------------------------------------------------------------
DISK_ID=$(echo "$SRC_PATH" | $AWK -F. '{print $NF}')
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
unset i j XPATH_ELEMENTS
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onevm show -x $VM_ID | $XPATH \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/VITASTOR_CONF \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/TYPE )
SRC_IMAGE="${XPATH_ELEMENTS[j++]}"
CLONE="${XPATH_ELEMENTS[j++]}"
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
TYPE="${XPATH_ELEMENTS[j++]}"
if [ "$CLONE" = "YES" ]; then
SRC_IMAGE="${SRC_IMAGE}-${VM_ID}-${DISK_ID}"
fi
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path ${VITASTOR_CONF}"
fi
#-------------------------------------------------------------------------------
# Revert to snapshot (== remove current image and recreate it as a clone)
#-------------------------------------------------------------------------------
SNAP_REVERT_CMD=$(cat <<EOF
set -e
$CLI ls --json "$SRC_IMAGE@$SNAP_ID" | jq -s -e '[ .[][] | select(.name == "$SRC_IMAGE@$SNAP_ID") ] | length > 0'
$CLI rm "$SRC_IMAGE" || true
$CLI create --parent "$SRC_IMAGE@$SNAP_ID" "$SRC_IMAGE"
EOF
)
ssh_exec_and_log "$SRC_HOST" "$SNAP_REVERT_CMD" "Error reverting snapshot $SNAP_ID for $SRC_IMAGE"

View File

@ -1,18 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
set -e
DRIVER_PATH=$(dirname $0)
DEP_FILE=$1
DEP_FILE_LOCATION=$(dirname $DEP_FILE)
HOST=$2
cat > $DEP_FILE
python3 $DRIVER_PATH/deploy_vitastor.py $DEP_FILE $DEP_FILE_LOCATION/vm.xml
cat "$DEP_FILE" | ssh "$HOST" "'${SCRIPTS_REMOTE_DIR:-/var/tmp/one}/vmm/kvm/deploy' '$DEP_FILE'"

View File

@ -1,57 +0,0 @@
#!/usr/bin/env python3
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
import base64
from sys import argv, stderr
from xml.etree import ElementTree as ET
dep_file = argv[1]
with open(dep_file, 'rb') as fd:
dep_txt = base64.b64decode(fd.read())
dep = ET.fromstring(dep_txt)
vm_file = argv[2]
with open(vm_file, 'rb') as fd:
vm_txt = base64.b64decode(fd.read())
vm = ET.fromstring(vm_txt)
ET.register_namespace('qemu', 'http://libvirt.org/schemas/domain/qemu/1.0')
ET.register_namespace('one', 'http://opennebula.org/xmlns/libvirt/1.0')
vm_id = vm.find('./ID').text
context_disk_id = vm.find('./TEMPLATE/CONTEXT/DISK_ID').text
changed = 0
txt = lambda x: '' if x is None else x.text
for disk in dep.findall('./devices/disk[@type="file"]'):
try:
disk_id = disk.find('./source').attrib['file'].split('.')[-1]
vm_disk = vm.find('./TEMPLATE/DISK[DISK_ID="{}"]'.format(disk_id))
if vm_disk is None:
continue
tm_mad = txt(vm_disk.find('./TM_MAD'))
if tm_mad != 'vitastor':
continue
src_image = txt(vm_disk.find('./SOURCE'))
clone = txt(vm_disk.find('./CLONE'))
vitastor_conf = txt(vm_disk.find('./VITASTOR_CONF'))
if clone == "YES":
src_image += "-"+vm_id+"-"+disk_id
# modify
changed = 1
disk.attrib['type'] = 'network'
disk.remove(disk.find('./source'))
src = ET.SubElement(disk, 'source')
src.attrib['protocol'] = 'vitastor'
src.attrib['name'] = src_image
if vitastor_conf:
# path to config should be added to /etc/apparmor.d/local/abstractions/libvirt-qemu
config = ET.SubElement(src, 'config')
config.text = vitastor_conf
except Exception as e:
print("Error: {}".format(e), file=stderr)
ET.ElementTree(dep).write(dep_file)

View File

@ -1,40 +0,0 @@
#!/bin/bash
# Vitastor OpenNebula driver
# Copyright (c) Vitaliy Filippov, 2024+
# License: Apache-2.0 http://www.apache.org/licenses/LICENSE-2.0
DRIVER_PATH=$(dirname $0)
source $DRIVER_PATH/../../etc/vmm/kvm/kvmrc
source $DRIVER_PATH/../../scripts_common.sh
FILE=$1
DST_HOST=$2
DEPLOY_ID=$3
VM_ID=$4
DS_ID=$5
XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(cat | $XPATH \
/VMM_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VITASTOR_CONF \
/VMM_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/IMAGE_PREFIX)
VITASTOR_CONF="${XPATH_ELEMENTS[j++]}"
IMAGE_PREFIX="${XPATH_ELEMENTS[j++]:-one}"
CLI=vitastor-cli
if [ -n "$VITASTOR_CONF" ]; then
CLI="$CLI --config_path $VITASTOR_CONF"
fi
SRC_IMAGE="${IMAGE_PREFIX}-sys-${VM_ID}-checkpoint"
ssh_exec_and_log "$DST_HOST" "$CLI dd iimg=$SRC_IMAGE of=$FILE" "Error exporting checkpoint into from $SRC_IMAGE to $FILE"
ssh_exec_and_log "$DST_HOST" "$CLI rm $SRC_IMAGE" "Error removing checkpoint $SRC_IMAGE"
set -e
ssh "$DST_HOST" "'${SCRIPTS_REMOTE_DIR:-/var/tmp/one}/vmm/kvm/restore' $@"

Some files were not shown because too many files have changed in this diff Show More